5 - Function-Palooza
ucla | CS 131 | 2023-11-13 00:14
Table of Contents
- Parameter Passing
- Returning Results and Handling Errors
- First class functions
- Polymorphism
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
- 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
- this can cause issues since local vars are out of scope if a block ends -> memory leaks
- 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 - 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++ - 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
- 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
- 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