COS 333: Chapter 9, Part 3
Summary
TLDRThis lecture concludes the discussion on sub-programs, focusing on overloaded sub-programs, generic sub-programs including C++ templates and Java generics, and design issues specific to functions. It delves into user-defined overloaded operators, closures, and coroutines, illustrating their practical applications and importance in programming. The lecture emphasizes the flexibility and power of these concepts in various programming languages, highlighting their role in creating efficient and versatile code.
Takeaways
- π The lecture discusses the final part of Chapter Nine, focusing on sub-programs, including overloaded sub-programs, generic sub-programs, design issues related to functions, user-defined overloaded operators, closures, and coroutines.
- π Overloaded sub-programs have the same name but different protocols, which include parameter types, numbers, and return types. They are supported by languages like C++, Java, C#, and Ada, with some differences in how they handle return types.
- π The concept of generic sub-programs, or polymorphic sub-programs, allows a sub-program to take different parameter types. C++ supports this with template functions, while Java uses generic methods, each with different underlying implementations.
- π€ C++ template functions are instantiated at compile time for each type used, whereas Java's generic methods work with a single runtime construct, using instances of the Object class for generic types.
- π« Design issues for functions include side effects, the number of values that can be returned, and the types of return values allowed, which vary across languages like C, C++, Ada, Java, and C#.
- π§ User-defined overloaded operators allow programmers to specify their own implementations for existing operators for new types, supported in languages such as Ada, C++, Python, and Ruby.
- π Closures, as illustrated in JavaScript, capture the environment in which they were created, allowing the function to access those variables even outside their original scope.
- β Coroutines are sub-programs with multiple entry points, allowing execution to be passed back and forth between them, useful for simulations and creating quasi-concurrent execution.
- π The execution of coroutines can be resumed and suspended, allowing for an interleaved execution flow that can be ideal for certain types of applications, like traffic light simulation.
- π The lecture also mentions that Chapter Ten, which covers the implementation of sub-programs, will be skipped, proceeding directly to Chapter Eleven on abstract data types and encapsulation.
Q & A
What is an overloaded sub-program?
-An overloaded sub-program is a sub-program that shares the same name with another sub-program in the same referencing environment, but has a different sub-program protocol, which includes a difference in the number, types of parameters, or the return type.
How do programming languages like C++, Java, C#, and Ada disambiguate overloaded sub-programs?
-These languages disambiguate overloaded sub-programs based on their parameter profile, meaning they look at the number and types of parameters involved in the call.
What is the impact of type coercion on disambiguating overloaded sub-programs?
-Type coercion can complicate the disambiguation process because it may change the types of parameters in a way that affects which overloaded version of a sub-program is selected.
Why can't the approach of using return types to disambiguate function calls work in languages like C++?
-In C++, overloaded sub-programs must differ in their parameter profiles; relying on differing return types alone is not sufficient to disambiguate them, as this could lead to redefinition conflicts.
What is a generic sub-program?
-A generic sub-program, also known as a polymorphic sub-program, is capable of taking different parameter types in different calls, supporting ad hoc polymorphism through overloading and parametric polymorphism through generic parameters.
How do template functions in C++ work behind the scenes?
-In C++, template functions create different versions of the function at compile time for each type that is used with the function, allowing for type-specific behavior.
What is the difference between template functions in C++ and generic methods in Java?
-Template functions in C++ create a new function version for each type at compile time, while Java's generic methods are instantiated once at runtime, using instances of the Object class for generic types.
Why must generic parameters in Java be classes and not primitive data types?
-Java's generic methods work with instances of the Object class behind the scenes, so they must be classes. Primitive types cannot be used because they are not objects and do not inherit from the Object class.
What are some design issues specific to functions?
-Design issues specific to functions include the allowance of side effects, the number of values that can be returned, and the types of return values permitted by the programming language.
How do closures work in JavaScript?
-Closures in JavaScript are created by factory functions that return anonymous functions. These closures capture the scope in which they were created, allowing them to access variables from outer functions even after those functions have finished executing.
What is a co-routine and how does it differ from a regular sub-program?
-A co-routine is a sub-program with multiple entry points that controls its own execution flow. It differs from regular sub-programs by allowing a more equal relationship between the caller and the called, and it can be paused and resumed at specific points, facilitating a form of interleaved execution.
Outlines
π Overloaded Sub-Programs and Generic Sub-Programs
This paragraph introduces the concepts of overloaded and generic sub-programs. Overloaded sub-programs are functions or procedures with the same name but different parameters or return types within the same scope, enabling polymorphism. The discussion then shifts to generic sub-programs, which can take different parameter types across various calls. The paragraph explains ad hoc polymorphism through overloaded sub-programs and parametric polymorphism, which is supported in languages like C++ and Java through templates and generics. It also touches on the implementation details of templates in C++, where different versions of a function are created at compile time based on the types used.
π Generic Sub-Programs in Java and C#
The second paragraph delves into the specifics of generic sub-programs in Java and C#. It contrasts Java's generics with C++ templates, highlighting that Java's generic parameters must be classes and cannot be primitive data types. The paragraph explains how Java's generic methods are instantiated at runtime and use instances of the Object class internally. It also discusses the benefits of Java's generics, such as automatic casting and error detection at compile time, and advanced features like restricting class ranges and using wildcard types.
π Design Issues in Functions and Return Values
This paragraph discusses design issues specific to functions, focusing on side effects, the number of values that can be returned, and the types of return values allowed. It mentions that most languages restrict functions to a single return value, with exceptions like Ruby and Lua that allow multiple return values. The paragraph also covers how different programming languages handle the return of complex types, such as user-defined types and function pointers, and the implications for language design.
π User-Defined Overloaded Operators and Closures
The fourth paragraph explores user-defined overloaded operators, which allow programmers to define custom behavior for existing operators with new types. It provides an example from Python, where the addition operator is overloaded for a complex number class. The paragraph then introduces closures, a feature supported by some languages, which allow the creation of anonymous functions that capture the environment in which they were created. It explains closures with an example from JavaScript, where a factory function creates and returns functions with closed-over variables.
π Coroutines: Sub-Programs with Multiple Entry Points
The final paragraph introduces coroutines as sub-programs with multiple entry points, controlled by the coroutine itself. It discusses how coroutines differ from regular sub-programs by allowing for a more equal relationship between the caller and the called. The paragraph explains the concept of resuming execution in coroutines, where the execution can be paused and resumed from the last statement executed. It also provides examples of how coroutines can be used for tasks like simulating traffic light control, where coroutines can hand off control to each other in a cyclic manner.
Mindmap
Keywords
π‘Sub-programs
π‘Overloaded Sub-programs
π‘Generic Sub-programs
π‘Template Functions
π‘Type Coercion
π‘Closures
π‘Co-routines
π‘User-defined Overloaded Operators
π‘Design Issues
π‘First-class Objects
Highlights
Overloaded sub-programs are defined as having the same name but different protocols, including parameter types or return types.
Some languages like C++ restrict overloading to parameter profiles, ignoring return types for overload resolution.
Type coercion can complicate the disambiguation of overloaded sub-programs in languages that support it.
Ada allows function overloading based on differing return types even if the parameters are the same.
Generic sub-programs, or polymorphic sub-programs, can take different parameter types in different calls.
Ad hoc polymorphism is the simplest form of generic sub-program, provided by overloaded sub-programs.
Parametric polymorphism allows a sub-program to take generic parameters, with different instantiations having different types.
C++ supports generic sub-programs through template functions, which are defined with a template clause.
Java's generics are different from C++ templates, with instantiation happening at runtime and using the Object class for type handling.
Java generics can restrict class ranges and use wildcard types, unlike C++.
C# also supports generic methods but without wildcards and with type inference capabilities.
Design issues for functions include side effects, the number of values that can be returned, and the types of return values allowed.
Some languages like Ruby and Lua allow functions to return multiple values, unlike most languages that restrict to a single value.
User-defined overloaded operators allow custom implementations for existing operators on new types.
Closures capture the environment in which they were created, allowing the use of variables outside their scope.
Coroutines are sub-programs with multiple entry points, allowing for a more equal relationship between caller and called.
Coroutines are useful for simulating concurrent execution in programs, such as traffic light control systems.
Transcripts
this is the third and final lecture on
chapter nine which deals with
sub-programs in this lecture we'll be
finishing off our discussion on the
chapter
these are the topics that we'll be
discussing in today's lecture we'll
begin by looking at overloaded sub
programs then we'll move on to generic
sub programs what you will know in c
plus as template functions
then we'll look at some design issues
that are specifically related to
functions and do not apply to procedures
and then we'll be looking at
user-defined overloaded operators
we'll then finish off our discussion by
looking at closures first of all and
then co-routines both of which are the
most important material discussed in
this lecture
now the first topic that we'll look at
in this lecture is overloaded
sub-programs so an overloaded
sub-program is quite simply a
sub-program that has the same name as
another sub program in the same
referencing environment
now of course these overloaded sub
programs cannot be exact duplicates of
one another otherwise we would be
redefining a startup program which is
generally speaking not allowed in a
programming language and therefore there
must be a difference between these
overloaded sub-programs and this
difference is in terms of the
sub-program protocol of each of the
overloaded sub-programs which must be
different
so recall from our discussion earlier on
in this chapter that a sub-program
protocol includes the number and types
of the parameters of the sub-program as
well as the return type of the
sub-program
so what this means is that overloaded
sub-programs are allowed as long as
there is at least one difference in
terms of a parameter or alternatively
the return type of the sub-programs that
are overloaded
now some programming languages further
restrict this to include just the
parameter profile and an example of a
language in this category would be c
plus
so in this case the parameters of
overloaded sub-programs must differ
if we have sub-programs that have the
same parameters but they differ in terms
of their return types this is not
allowed and these programs would be
considered to clash with one another and
would be redefinitions of the same sub
program
so to look at overloaded sub programs in
the context of real world programming
languages we see that c plus java c
sharp and ada all support overloaded sub
programs and they disambiguate these
sub-programs based on their parameter
profile only so in other words they
don't consider the return type of the
sub-programs
now of course type coercion in these
programming languages complicates the
mapping process a little
and this of course depends on how the
overloaded sub-programs are implemented
and what the type coercion rules of the
specific programming language are
so what i would like you to do at this
point is to pause the video and try to
explain what problems type coercion will
introduce in terms of disambiguating
overloaded sub-programs in these
languages
now in ada the return type can also be
used to disambiguate function calls
and so what this means is overloaded
functions can have exactly the same
parameters as long as their return types
differ
so what i would like you to do once
again is pause the video here and try to
explain why this approach can't work in
languages like c plus
next we'll move on to generic sub
programs
so generic or polymorphic sub programs
take different parameter types in
different calls
now the first and simplest kind of
generic sub program is provided by means
of ad hoc polymorphism
and this is provided to us by means of
overloaded sub programs which we've just
discussed now there is a second kind of
generic sub-program that exists which is
provided by means of parametric
polymorphism this isn't supported in all
programming languages but notably is
supported in languages like c plus and
java
so with parametric polymorphism a sub
program takes what is referred to as a
generic parameter
and a generic parameter describes the
types of the sub-program's parameters
and then different instantiations of the
same sub-program get different generic
parameters so for example we may have a
sub-program that receives two parameters
these parameters are of a generic type
we can then create one instantiation of
the sub program where this generic type
is an integer type meaning that the sub
program receives two integer parameters
and then we can create a second
instantiation of the sub program where
the generic
parameter is a floating point value in
which case the sub program will then
receive two floating point parameters
instead
so as i just mentioned c plus supports
generic sub programs and these are
referred to as template functions
we will in c plus plus define a function
and then proceeded with a template
clause and the template clause lists the
generic variables
and variables can take on type names as
well as class names so over here we have
an example of a generic sub program or a
template function in c
we can see that our function definition
is preceded by a template clause where
we specify that there's one generic type
which is specified as t
we then specify our sub program in this
case a function called max and we can
see that we've specified that it
receives two parameters first and second
and the type of first as well as the
type of second will be t which is our
generic type we also specify that the
return type of our max function is also
t
inside the body of our max function we
compare first and second to one another
and if first is greater than second then
we return first otherwise we return
second
so notice that what we are assuming here
is that the type t supports this
inequality comparison in other words we
can test to see where the first is
greater than second if we attempt to use
a type 40
with our max function that doesn't
support this greater than comparison
then there will be some kind of
compilation error that will be raised
so now let's get into how tempted
functions in c plus actually work behind
the scenes
again we'll assume this template
function or generic sub program from our
example on the previous slide
now what's important to understand in c
plus is that different versions of this
sub program the max function in our
example over here are created at compile
time and this happens whenever new types
for t are used when either the sub
program is called or if we're working
with function pointers if the address of
the sub program is taken using the
ampersand operator
on this slide we have a practical
example down here of how the max
function is used in terms of a call so
over here we can see we are calling the
max function we're passing through
two actual parameters a and b
and we are assigning the result returned
by max to a variable c
we can see that the types of a b and c
are int in all cases although the type
of c is less critical
in this example because of type coercion
rules so what this means then is that
the c plus compiler will encounter this
call to our max function and it will see
that the types of the parameters are
integers
so it will then generate a new version
of our max function
where the type int is used wherever t
appears within the function definition
it's important to understand that this
version is created at compile time and
it's an entirely separate version of the
max function
if we were to use the max function with
float parameter types then once again
the compiler would encounter this and it
would generate a second version of our
max function
except where t appears we would now have
float which would replace all of those
occurrences of
t generic sub-programs are also
supported in java 5 in which case we
refer to these sub-programs as generic
methods now it's important to understand
that generics in java differ from
template functions in c plus and we'll
spend the next few slides discussing
these differences
so the first and simplest difference is
that generic parameters in java must be
classes
and they are not allowed to be primitive
data types such as int or float
so over here we have an example of a
generic method in java our method is
called do it it is a static method which
is defined to be public within the class
it is defined for and we can see that we
have specified a generic type t within
these angled brackets over here we've
also specified that as a parameter the
do it method receives a list which is an
array that contains t
values
we also have a return type for our do it
method which is also of type t
so what this thing means is we can
legally use the doit method as we can
see over here so here we are calling our
do-it method we have to specify in java
in angled brackets what the generic type
is in this case we've specified that
it's a string
now this is legal because string is an
object it isn't a primitive type like an
int or a float
we then pass through as a parameter to
the do it method my list which we can
see has been specified up here so my
list is an array that contains string
objects once again our generic type is
string and then we've simply specified
that this is a new string with space
allocated 14 string objects
so let's look at how generic methods in
java actually work behind the scenes
once again we'll assume our generic do
it method as well as this call to the do
it method
now what's very important to understand
is that in java generic methods are
instantiated only once and this happens
at run time so this is different to c
plus
where a generic template function has a
different version generated for every
type that it is used with
and these different versions of the
generic template function are generated
at compile time instead there is only
one version of a generic method and this
is a runtime construct so what this
means in terms of our example over here
is that there is only one occurrence of
the do it method and this is a runtime
construct
now what actually happens is that
instances of the object class are used
wherever the generic type t appears
so in our do it method we see that the
parameter is an array that contains
t
objects
actually behind the scenes what happens
is the duet method receives an array
that contains instances of the object
class
similarly the do-it method returns a
generic type t but what actually happens
behind the scenes is that it returns an
object
now
the do it method then can in fact
receive and return any particular object
and this is because objects inherit from
the object class in java
so in terms of our parameter we see that
we are receiving an array of objects
what this means is that the do it method
can receive an array of any particular
object because all objects in java
inherit from the object class
in a similar fashion we can return any
particular object because once again all
objects in java inherit from the object
class
so this explains why generic types in
java must be classes
and they cannot be primitive types like
ins or floats and so the reason for this
is that we are actually storing and
working with
instances of the object class behind the
scenes
so the question that naturally arises
then at this point is why don't we
simply define our do-it method
using objects as we saw in our previous
example and the reason for this is that
generics in java
allow the compiler to automatically
insert costs to the appropriate type and
this improves the error detection of our
code
so in our example of the do it method
over here the compiler will insert two
costs for us if we are using the do-it
method with the type of string
so firstly it will cost the parameter
which is this list over here and its
type is an object array will
automatically insert a cost that
converts list into a string array
it will also automatically insert a cost
for the returned object to type string
so what this means then is that if there
is a type misuse then this will be
picked up at compile time rather than at
run time so let's say for example that
somebody were to try to use the do it
method but instead of then passing
through an array of strings as in our
example over here where we pass through
my list which has the correct type we
instead passed through an array of
student objects
now with this version of the do it
method without the automatic costs
inserted we would not get a compile time
area because we are still passing
through an array of objects which is
correct it will only be inside the
implementation of the duet method where
we will then get a runtime error because
we will be trying to retrieve student
objects from this array and that of
course will not work
in a similar fashion if we attempt to
for example return a student object from
the do it method then this will also be
picked up at compile time because of the
automatic cost that has been inserted
in our version with just objects without
this cost automatically inserted we
won't get that error picked up until
runtime where the returned object is
actually used and at that point the type
mismatch is then detected
so what's very important to understand
then at this point is that generics in
java are actually not a necessity and in
fact earlier versions of java prior to
version 5 didn't support generics
generics simply include these additional
costs which make our programming a lot
safer and highlight errors much earlier
than runtime where they would ordinarily
be detected
generics in java also provide a little
bit of additional functionality that c
plus doesn't provide so firstly we can
restrict class ranges for generic
parameters and that's exactly what we've
done in this example over here
so here once again we've got a do it
method and this works with a generic
type t and once again we can see that
we've used t both in the parameter and
the return for the do it method however
additionally we have specified in the
angled brackets that t
explains comparable so what this means
is that t must be a sub type of
comparable which means that t must be a
class that either inherits from a class
called comparable or it implements an
interface called comparable now in this
particular example comparable is an
interface that is provided by the java
programming language itself
now java 5 also allows for wild card
types to be specified for generic
parameters as we can see in this example
over here
so here we've specified a method called
print collection that returns nothing
however it receives a parameter called c
which is a collection object now the
collection class is a generic class that
contains instances of a particular
generic type so we've specified a
question mark for this generic type in
the angled brackets after the collection
class name
and this question mark means any object
so what this means is that the print
collection method can receive an
instance of the collection class that
contains objects of any particular class
now it is also possible for us to
restrict this wild card question mark
symbol using the extends special word in
which case we then restricted to inherit
from or implement an interface that we
have specified similar to what we saw on
the previous slide
finally c-sharp 2005 also supports
generic sub-programs in the form of
generic methods which are similar to the
generic methods that we saw in java 5.
there are two main differences firstly c
sharp does not support wild cards the
way that java does
and secondly if the c sharp compiler can
infer the unspecified type then the
actual type parameters in the call can
be emitted so we see that in this
example over here
here we have specified a generic method
called do it we specify that there is a
single generic type namely t
and we've specified that the type of the
parameter for doit is t
and also the return type for the do it
method is t
now here we have two calls to the doit
method the first one we can see over
here
since through an integer parameter which
is 17 and we can also see that the
return of the doit method is assigned to
an integer variable called myint
so what this means then is that the
compiler will automatically infer that
the generic type for this call should be
an int
in a similar fashion here we have a
second call to the doit method here
we're passing through a string
apples as the parameter and also the
return of the call to do it is assigned
to a string variable called mystr
so in this case also the c-sharp
compiler will determine that the generic
type should be string
now in java we always have to specify
the generic type in the call so for
example with the second call we would
have to place angled brackets after the
do it method name and specify that the
type is string for this particular call
next we'll look at three design issues
that apply specifically to functions
recall that a function is a sub-program
that produces a result by means of a
return
so the first of these design issues
relates to where the side effects are
allowed for functions and we've already
spoken about this in quite a lot of
detail in chapter 15 so i won't repeat
that discussion here
however what does bear mentioning is
that to reduce side effects we generally
speaking want parameters to be in mode
only and some programming languages such
as ada enforce this however most
programming languages do not
the second design issue specific to
functions is how many values can be
returned by a function
so most programming languages restrict
the number of returned values to only a
single value however ruby and lua are
two notable exceptions to this rule
so ruby methods allow for multiple
values to be returned and we see that in
this example over here here we have a
method called multiple values and we can
see that we are returning several values
where the values are separated by means
of commas now what actually happens
behind the scenes is that ruby will
package these values together within an
array which will be returned now of
course we can use arrays to simulate
multiple return values in any
programming language that supports
arrays
now lua functions also allow for
multiple return values and these work by
means of multiple target assignments
which we discussed in chapter 7 and you
can review that chapter in order to see
a few code examples of how these
multiple return values would work in
practice
the final design issue specific to
functions relates to what types of
return values are allowed for functions
now different programming languages have
different approaches to which return
types are allowed and so we'll look at a
couple of practical examples on this
slide
so c and c plus plus functions allow any
type to be returned except for arrays
and functions however functions in these
languages can return pointers rather
than arrays
and function pointers rather than
functions themselves
c plus plus of course also allows user
defined types to be returned by
functions
ada sub programs can return any
particular type however in ada sub
programs are not considered to be types
and therefore ada sub programs can't
return sub programs
java and c sharp methods can both return
any type however in both of these
languages methods are not considered
types and therefore methods cannot
return methods within these two
languages
and then finally in python ruby and lua
any class can be returned and methods
are also considered to be first class
objects so therefore methods can also be
returned within these programming
languages
some but not all programming languages
support user-defined overloaded
operators and in these languages the
programmer can specify their own
implementations
for existing operators within the
programming languages but for new types
so user-defined overloaded operators are
supported in ada c plus python and ruby
and over here we have an example of a
user-defined edition operator that is
specified in python we're assuming that
this operator is implemented for the
complex class in python which is a class
that represents complex numbers complex
numbers consist of a real part and an
imaginary part
so here we are defining a subprogram
called add and this is a special
reserved sub program name
that indicates we are defining an
addition operator
we have two parameters for this sub
program
self is the left operand and second is
the right operand for the operator and
both self and second have the type of
complex
so then we have the body of our user
defined overloaded edition operator and
this creates a new object of type
complex and it sets the real part to the
addition of the left and right operands
real parts and the imaginary part of the
new complex
object to the sum of the imaginary parts
for the left and right operands
so this operator then is defined for two
complex objects and if we assume that x
and y are two complex objects then these
are the two ways in which this operator
can be used so firstly we can explicitly
call this add subprogram sending through
as a single parameter the right operand
and we specify the left operand as the
object that the add method is called on
alternatively we can simply use the
operator notation where we use the plus
symbol in order to add x and y to one
another
next we'll take a look at closures and
closures are very important for test and
exam purposes
so over here we have a simple example
that illustrates how closures work in
javascript
here we have a function called make
adder and as you can see make adder
receives a single parameter
namely x
now the make adder function creates a
new function which is an anonymous
function because it doesn't have a name
associated with it
so make adder creates this function and
then returns it so you can think of the
make adder function as a factory that
creates new functions
now this anonymous function that is
created it receives a single numeric
parameter which is called y
and it returns then y plus another value
which is specified by means of x which
is the parameter that has been sent
through to make adder so essentially
make adder then constructs functions but
it can parameterize those functions
depending on inputs sent in to make
adder by means of its parameter
in order for a closure in javascript to
be used we need to assign the anonymous
function which is the closure to a
variable so that's exactly what we do
over here here we call make adder and we
pass through a parameter of 10 to that
so in other words x will then have a
value of 10. what this means then is
that we return a new anonymous function
which is in our closure where x now has
a value of 10. so this is the form of
the function that will be returned we
can see that x's value is 10 over here
the function receives a single parameter
y and we return tin plus y
that function is then assigned to the
variable add team
in a similar fashion here we call make
adder with a parameter value of five
so in this case then x's value that is
sent through is five so this is then the
form of our anonymous function that gets
returned by make adder we are receiving
a single parameter y for this function
and we are returning five plus y
this anonymous function is then assigned
to the variable add five so what we can
now do is we can call these anonymous
functions by means of the variables add
10 and add 5 and that's exactly what we
do at this point and this point within
our program
so at this stage here we are now calling
an anonymous function that has been
returned by make added through the
variable at 10
and this will then add 10 and whatever
parameter value has been seen through
which in this case is 20 and therefore
the result returned by that call will be
30. in a similar fashion over here we
are calling add 5 which is the variable
referring to our anonymous function
and we are sending through a parameter
value of 20 to that that will then add 5
and 20 and return a value of 25.
now let's for the purposes of our
example assume that we call make adder
with a parameter value of 10 but instead
of sending through a literal value of 10
as we do in this example we instead have
a variable with a value of 10 which we
then pass through as the parameter to
make adder
now what's important to understand is
that the closure that is returned by
make adder is assigned to a variable and
this variable can be passed around it
can be synced to another sub-program for
example and it could be executed at any
particular time and what may happen is
that the variable that we pass through
as the parameter to make adder may have
gone out of scope by the stage that add
team is called
so
what this then means is that javascript
must maintain the storage for whichever
variable has been passed through to make
adder and it must maintain this for the
entire program execution and the reason
for this is that the closure can be
called at any point through the course
of program execution we can't be sure
when it will actually be called so what
this means is that any variable passed
to make adder must then exist from that
point on through the course of the
entire execution of the program until
the program eventually terminates and
what we would then say is that this
variable has unlimited extent
the final topic that we'll get to in
this chapter is co-routines and
co-routines are also very important for
test and exam purposes and are
relatively easy to understand so i
recommend paying some attention to them
so a co routine then is a sub program
with multiple entry points and the
co-routine itself controls these entry
points
coroutines are directly supported within
lua but not many other programming
languages
coroutines are sometimes also referred
to as metric control mechanisms and this
is because the caller and the called
co-routines exist on a more equal basis
than what we see with regular
sub-programs where there's a definite
hierarchical relationship between the
caller and the called sub program
now the method for calling a co routine
is referred to as a resume and a resume
does one of two things depending on when
it is called so the first time that a
resume is called for a co routine it
begins execution at the beginning of
that co routine
then if we call a resume after
the first time that it has been executed
it will then pause the execution of the
co-routine that is executing the resume
and it will begin execution after the
last executed statement for the
co-routine that is being resumed
so what this thing means is we can have
cycles set up where co-routines can
resume one another forever
and this allows then a kind of a
quasi-concurrent execution of program
units where the execution is interleaved
but it is not overlapped
so
co-routines are perfect for simulation
style software for example if we are
simulating a traffic light intersection
so we might then have one subroutine
that operates for a pair of traffic
lights facing one another and then a
second subroutine that operates for the
pair of traffic lights at right angles
to the first pair
so what would happen then is as the
first pair of traffic lights would
transition to red then they would call a
resume on the co routine dealing with
the set of traffic lights at right
angles which would then start up and
begin executing from where they last
left off therefore turning those traffic
lights green and then cycling through to
red again at which point a resume would
be called for the first pair of traffic
lights and so resumes can then be passed
back and forth between these two
co-routines and continuously control can
then be hand handed from one to the
other and back again we'll look at some
examples of how this would work in
practice
in the next three slides
so here we have a simple example of two
co-routines that resume one another
we assume that our first co-routine is
called a and our second co-routine is
called b
we then have a master which you can
think of as a main
function
and this then calls a resume on
co routine a so this begins execution at
the top of a and execution will continue
until we reach this resume for b
now there hasn't been a resume that has
been called for co routine b yet so at
this point control then moves up to the
top of co routine b and we execute then
a series of statements until we get to
this next resume which is then 4a so at
this point control then passes back to a
but we continue executing from where we
left off so in other words not the top
of the a co routine but instead from
this point on until we reach our next
presume over here this thing passes
control back to b
at the point where we left off so we
continue executing down from that point
until we reach another resume which
again passes control back to a where we
left off we continue executing down and
then finally reach this last resume over
here which passes control back to b
where we again continue where we left
off and then finally co routine b will
then terminate
here we have a similar example to the
one that we looked at on the previous
slide this time however our first resume
is for co-routine b
so again we begin executing at the top
of b we then reach a resume for co
routine a at this point no resume has
been called on curitin a yet so we pass
control to the top of curitin a and
begin executing from there down we then
reach another regime four core routine b
so at this point execution of curitin a
is suspended we then move control over
to co-routine b and continue executing
from where we left off so we execute
these statements reach another resume
for co-routine a so again we suspend co
routine b
pass control back to co-routine a where
we left off continue executing from
there reach another resume for
corrupting b pass control back to b and
then finally terminate co routine b
this final example illustrates how
control can be passed back and forth
indefinitely between two coroutines
so in this example we once again have
two co-routines a and b
and our initial resume from our master
sub program is for co-routine a
now what's important to note here is
that co-routines a and b both contain
loops so the initial resume will begin
execution at the top of co-routine a and
will then enter our loop at which point
we will then reach after a number of
statements our first resume for
co-routine b
so this point control is passed to co
routine b we begin executing at the top
and we enter our loop execute a series
of statements and then we reach a resume
for a so this again passes control back
to a and we then begin executing from
the point where we left off we loop back
again and then we get to our resume for
b once more which then passes control
back to b and we continue executing from
the point where we left off loop back
and then reach a resume for a
so we continue back and forth in and we
will continue forever passing control
back and forth between co-routines a and
b
until eventually some sort of
termination condition is reached
all right so that concludes then our
discussion on chapter nine we will be
skipping over chapter 10 which deals
with how sub programs are implemented
and we will in the next lecture be
moving on to chapter 11 where we will
discuss abstract data types and
encapsulation concepts
5.0 / 5 (0 votes)