5 - Function-Palooza

ucla | CS 131 | 2023-11-13 00:14


Table of Contents

Parameter Passing

  • terminology of params/args when defined vs. called
  • 3 main types of parameter passing semantics - akin to value binding semantics
  • Pass by Value (Copy)

  • the passed value i evaluated to get a value (complete deepcopy) that it uses
  • nothing about the original args is changed

Pass by Reference (Address)

  • secretly passes the address of the args
  • thus ANY changes to the passed params WILL reflect on the original args
  • Pass by Object Reference (Pointers)

  • all passed args are passed with pointers
  • thus modifying the formal parameter (using its mutator) -> modifies the pointed-to object
  • BUT, reassignment just reassigns the pointer not the passed arg, UNLESS we dereference the pointer

Pass by Need (Name)

  • lazy evaluation, same as name binding semantics
  • used in haskell, for ex.
  • saves a blank value that refers to the expression that will be evaluated when necessary

    Aliasing

  • when two params refer to the same object in references/objet references

Determine Parameter Passing Semantics

Positional, Named, Default, Optional Parameters

  • default params must be declared as formal parameters after all positional to prevent aliasing
  • you can pass args positionally or named
  • Variadics: Args and Kwargs

  • optional params, you can pass as many as you want
  • *args = any number of unnamed args
  • **kwargs = any number of keyword (named) args

Returning Results and Handling Errors

  • Error Objects

  • Recoverable errors and results
  • lang-specific objects to explicitly return an error
  • error classes are usually provided by the lang
  • some langs return values along with an error

Result and Optional Objects

  • Recoverable errors and results
  • only difference is what is returned in an error
  • result object - returns full error details with an error object
  • optional object - returns some arbitrary comment on a failure
  • Result Objects

  • creates return objects for each case: success, failure
  • use pattern matching to get the right value
  • Optional Objects

Assertions: Pre/Post Conditions and Invariants

  • Used for Bugs and Unrecoverable errors
  • we use an assertion to assert/verify the following
  • Assertions: Pre/Post Conditions

  • assertions will immediately terminate the program if the assertion is not met
  • pre/post conditions are sometimes set explicitly, e.g., Eiffel lang
    • Assertions: Invariants

  • used in the body of the function to ensure conditions during execution are met

When to use assertions?

  • impossible to use for every op
  • use at a functional level like the previous stack example
  • use when something may go very wrong: undefined behavior, unintended consequences

    Exception Handling

  • Bugs, Unrecoverable errors, and Recoverable errors
  • other error handling is used directly in the code -> makes flow hard to read
  • exception handling separates error handling from the body of func
  • uses a catcher and thrower
  • if at any time an op in the try block causes an error -> immediately catch the error and deal with it
  • the thrower will take the return -> and throw if there is a failure
  • Exception Handling Flow

  • exceptions can catch through nested function calls
    • this can cause issues since local vars are out of scope if a block ends -> memory leaks
      • must use smart pointers in C/C++
      • or must define whether or not a lang throws an error like Java
  • can be used to catch specific errors
  • if there is no compatible catch when an error is thrown -> prog terminates
  • this is equivalent to a “panic.”
  • to handle issues with open connections, etc. sometimes, langs have a finally block that always runs regardless of a catch
    • finally will always run so returns in the try block can be overwritten
    • What is an exception

  • an object with one or more fields to describe an exceptional situation
  • but you can subclass exceptions to make your own

Guidelines: Exception Guarantees

  • Panics

  • Bugs and Unrecoverable errors
  • aborts execution due to an exceptional situation
  • basically an exception which is never caught -> returns description and stack trace

    Error Handling Best Practices

First class functions

  • first-class functions - can be passed as params and returned, vars can be assigned to funcs, funcs can be stored in data structures, can be compared and expressed anonymously
  • second class funcs - funcs caan be paassed as args but not assigned to vars or returned
  • third class funcs - can be called, thats it
  • Examples
    • C++ - first class w/ function pointers
    • Go - first class except equality
    • Python - fully first class
      • Lambdas

  • C++ - captured free variables are left unchanged outside lambdas
  • C++ - must define free vars, or make them capture all or none
  • Lambdas can be unpure - cause external effects, e.g. event handlers
  • Examples

Polymorphism

Subtype Polymorphism

  • What we are used to

    Ad-Hoc Polymorphism

  • only for statically typed langs to differentiate
  • dynamically typed langs cannot know what to call bc types are determined at run time
    • instead check types within the single function bc of duck typing

Parametric Polymorphism

  • define single parametrized version that can operate on multiple types that are decided at usage/implementation
  • C++ - one of the few langs that uses templated types to implement parametrization, most others use generic types
  • Examples and usage
    • Templates

  • the compiler creates new concrete functions for each templated type used
  • the compiler will check compatibility during compile time when recreating a type-specific function for each templated class
    • Macros

  • used in C before templates in C++
  • Generics (Unbounded)

  • looks very similar to templates, BUT the code inside generics must be type agnostics
  • thus all operations must be applicable to all classes/types
  • thus no calling .sleep() or something like that
  • BUT type checking is still done at parametrization (usage)
  • Bounded Generics (Generic with types constrained)

  • we can bind a generic to operate on specific types:
  • And we can create bounded classes
  • and use parametrized polymorphic functions on these bounded classes
  • generics allow use to have type safety and ensure we use the generic type instead of using some other super high-level supertype object that would allow any types to be used

    Specialization

  • Ad-hoc polymorphism by creating a type-specific function for a templated function to make the function more optimal for a specific type
  • the dedicated version (top) is used instead of generic/templated (bottom) WHEN bool is passed in