COS 333: Chapter 9, Part 3

Willem van Heerden
30 Sept 202141:09

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

00:00

πŸ“š 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.

05:02

πŸ”„ 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.

10:03

πŸ›  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.

15:04

πŸŽ› 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.

20:04

πŸ”„ 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

Sub-programs refer to smaller units of code within a larger program that can be called upon to perform specific tasks. They are a fundamental concept in programming, allowing for code reusability and organization. In the video, sub-programs are discussed in the context of various programming languages and their capabilities, such as overloading and generic programming.

πŸ’‘Overloaded Sub-programs

Overloaded sub-programs are functions or procedures that have the same name but differ in the number or type of parameters they accept. This concept allows a single operation to be performed in different ways depending on the input. The script explains that these sub-programs must have a distinct sub-program protocol, which includes differences in parameters or return types.

πŸ’‘Generic Sub-programs

Generic sub-programs, also known as polymorphic sub-programs, are capable of operating on different data types. They are used to write flexible and reusable code. The script discusses two types of generic sub-programs: ad hoc polymorphism, provided through method overloading, and parametric polymorphism, where a sub-program is defined with generic parameters that can be instantiated with different types.

πŸ’‘Template Functions

Template functions are a feature in C++ that allow for the creation of generic sub-programs. They define a blueprint for functions that can work with different data types, specified as parameters when the template is instantiated. The script provides an example of a template function named 'max' that can compare two values of a generic type 'T'.

πŸ’‘Type Coercion

Type coercion is the implicit conversion of one data type to another. It can complicate the disambiguation of overloaded sub-programs because the compiler may automatically convert types to match the expected parameter type. The script mentions that type coercion rules depend on the specific programming language and how overloaded sub-programs are implemented.

πŸ’‘Closures

Closures are functions that capture and 'close over' the environment in which they were created, allowing them to access variables from outside their scope. In the script, closures are exemplified with JavaScript, where a factory function 'makeAdder' creates and returns anonymous functions that remember the value of 'x' passed to 'makeAdder'.

πŸ’‘Co-routines

Co-routines are sub-programs that can suspend and resume their execution at multiple points. They are used for tasks that require intermittent execution, such as event handling or simulations. The script describes co-routines as having multiple entry points and being able to pass control back and forth between each other, creating a cycle of execution.

πŸ’‘User-defined Overloaded Operators

This concept allows programmers to define their own behavior for operators when applied to user-defined types. The script gives an example from Python, where the addition operator '+' is overloaded for complex numbers, allowing two complex objects to be added together using the '+' symbol.

πŸ’‘Design Issues

Design issues refer to considerations and decisions that programmers must make when creating functions. The script discusses three specific issues: side effects, the number of values that can be returned by a function, and the types of return values allowed. These issues impact the functionality, readability, and usability of functions across different programming languages.

πŸ’‘First-class Objects

In programming, first-class objects are entities that can be treated like any other value in the language. This includes being able to be passed as arguments to functions, returned from functions, and assigned to variables. The script mentions that methods in Python, Ruby, and Lua are considered first-class objects, allowing for greater flexibility in how functions can be used and manipulated.

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

play00:01

this is the third and final lecture on

play00:04

chapter nine which deals with

play00:06

sub-programs in this lecture we'll be

play00:09

finishing off our discussion on the

play00:11

chapter

play00:14

these are the topics that we'll be

play00:16

discussing in today's lecture we'll

play00:18

begin by looking at overloaded sub

play00:21

programs then we'll move on to generic

play00:25

sub programs what you will know in c

play00:28

plus as template functions

play00:31

then we'll look at some design issues

play00:33

that are specifically related to

play00:36

functions and do not apply to procedures

play00:40

and then we'll be looking at

play00:42

user-defined overloaded operators

play00:46

we'll then finish off our discussion by

play00:48

looking at closures first of all and

play00:51

then co-routines both of which are the

play00:54

most important material discussed in

play00:57

this lecture

play01:01

now the first topic that we'll look at

play01:03

in this lecture is overloaded

play01:05

sub-programs so an overloaded

play01:07

sub-program is quite simply a

play01:09

sub-program that has the same name as

play01:12

another sub program in the same

play01:14

referencing environment

play01:16

now of course these overloaded sub

play01:18

programs cannot be exact duplicates of

play01:20

one another otherwise we would be

play01:22

redefining a startup program which is

play01:24

generally speaking not allowed in a

play01:27

programming language and therefore there

play01:29

must be a difference between these

play01:32

overloaded sub-programs and this

play01:34

difference is in terms of the

play01:37

sub-program protocol of each of the

play01:40

overloaded sub-programs which must be

play01:43

different

play01:44

so recall from our discussion earlier on

play01:47

in this chapter that a sub-program

play01:49

protocol includes the number and types

play01:52

of the parameters of the sub-program as

play01:55

well as the return type of the

play01:57

sub-program

play01:58

so what this means is that overloaded

play02:01

sub-programs are allowed as long as

play02:03

there is at least one difference in

play02:06

terms of a parameter or alternatively

play02:09

the return type of the sub-programs that

play02:13

are overloaded

play02:15

now some programming languages further

play02:17

restrict this to include just the

play02:20

parameter profile and an example of a

play02:23

language in this category would be c

play02:26

plus

play02:27

so in this case the parameters of

play02:30

overloaded sub-programs must differ

play02:33

if we have sub-programs that have the

play02:35

same parameters but they differ in terms

play02:37

of their return types this is not

play02:39

allowed and these programs would be

play02:42

considered to clash with one another and

play02:44

would be redefinitions of the same sub

play02:47

program

play02:50

so to look at overloaded sub programs in

play02:52

the context of real world programming

play02:54

languages we see that c plus java c

play02:58

sharp and ada all support overloaded sub

play03:01

programs and they disambiguate these

play03:04

sub-programs based on their parameter

play03:07

profile only so in other words they

play03:09

don't consider the return type of the

play03:11

sub-programs

play03:13

now of course type coercion in these

play03:15

programming languages complicates the

play03:17

mapping process a little

play03:20

and this of course depends on how the

play03:22

overloaded sub-programs are implemented

play03:24

and what the type coercion rules of the

play03:27

specific programming language are

play03:29

so what i would like you to do at this

play03:30

point is to pause the video and try to

play03:33

explain what problems type coercion will

play03:36

introduce in terms of disambiguating

play03:39

overloaded sub-programs in these

play03:41

languages

play03:46

now in ada the return type can also be

play03:49

used to disambiguate function calls

play03:52

and so what this means is overloaded

play03:54

functions can have exactly the same

play03:56

parameters as long as their return types

play03:59

differ

play04:00

so what i would like you to do once

play04:02

again is pause the video here and try to

play04:05

explain why this approach can't work in

play04:08

languages like c plus

play04:15

next we'll move on to generic sub

play04:17

programs

play04:18

so generic or polymorphic sub programs

play04:21

take different parameter types in

play04:24

different calls

play04:25

now the first and simplest kind of

play04:27

generic sub program is provided by means

play04:30

of ad hoc polymorphism

play04:32

and this is provided to us by means of

play04:36

overloaded sub programs which we've just

play04:38

discussed now there is a second kind of

play04:41

generic sub-program that exists which is

play04:43

provided by means of parametric

play04:46

polymorphism this isn't supported in all

play04:49

programming languages but notably is

play04:51

supported in languages like c plus and

play04:55

java

play04:56

so with parametric polymorphism a sub

play04:59

program takes what is referred to as a

play05:02

generic parameter

play05:04

and a generic parameter describes the

play05:06

types of the sub-program's parameters

play05:10

and then different instantiations of the

play05:12

same sub-program get different generic

play05:15

parameters so for example we may have a

play05:19

sub-program that receives two parameters

play05:22

these parameters are of a generic type

play05:25

we can then create one instantiation of

play05:28

the sub program where this generic type

play05:30

is an integer type meaning that the sub

play05:32

program receives two integer parameters

play05:35

and then we can create a second

play05:37

instantiation of the sub program where

play05:39

the generic

play05:41

parameter is a floating point value in

play05:44

which case the sub program will then

play05:46

receive two floating point parameters

play05:49

instead

play05:53

so as i just mentioned c plus supports

play05:56

generic sub programs and these are

play05:58

referred to as template functions

play06:01

we will in c plus plus define a function

play06:04

and then proceeded with a template

play06:07

clause and the template clause lists the

play06:09

generic variables

play06:12

and variables can take on type names as

play06:15

well as class names so over here we have

play06:18

an example of a generic sub program or a

play06:22

template function in c

play06:25

we can see that our function definition

play06:28

is preceded by a template clause where

play06:30

we specify that there's one generic type

play06:33

which is specified as t

play06:36

we then specify our sub program in this

play06:39

case a function called max and we can

play06:42

see that we've specified that it

play06:43

receives two parameters first and second

play06:47

and the type of first as well as the

play06:49

type of second will be t which is our

play06:52

generic type we also specify that the

play06:56

return type of our max function is also

play07:00

t

play07:01

inside the body of our max function we

play07:04

compare first and second to one another

play07:07

and if first is greater than second then

play07:09

we return first otherwise we return

play07:13

second

play07:14

so notice that what we are assuming here

play07:17

is that the type t supports this

play07:19

inequality comparison in other words we

play07:22

can test to see where the first is

play07:25

greater than second if we attempt to use

play07:28

a type 40

play07:31

with our max function that doesn't

play07:33

support this greater than comparison

play07:35

then there will be some kind of

play07:37

compilation error that will be raised

play07:42

so now let's get into how tempted

play07:45

functions in c plus actually work behind

play07:48

the scenes

play07:49

again we'll assume this template

play07:52

function or generic sub program from our

play07:56

example on the previous slide

play07:58

now what's important to understand in c

play08:01

plus is that different versions of this

play08:05

sub program the max function in our

play08:07

example over here are created at compile

play08:11

time and this happens whenever new types

play08:14

for t are used when either the sub

play08:17

program is called or if we're working

play08:20

with function pointers if the address of

play08:23

the sub program is taken using the

play08:26

ampersand operator

play08:31

on this slide we have a practical

play08:33

example down here of how the max

play08:37

function is used in terms of a call so

play08:41

over here we can see we are calling the

play08:43

max function we're passing through

play08:45

two actual parameters a and b

play08:49

and we are assigning the result returned

play08:52

by max to a variable c

play08:55

we can see that the types of a b and c

play08:58

are int in all cases although the type

play09:01

of c is less critical

play09:03

in this example because of type coercion

play09:06

rules so what this means then is that

play09:09

the c plus compiler will encounter this

play09:13

call to our max function and it will see

play09:17

that the types of the parameters are

play09:19

integers

play09:20

so it will then generate a new version

play09:23

of our max function

play09:25

where the type int is used wherever t

play09:28

appears within the function definition

play09:32

it's important to understand that this

play09:34

version is created at compile time and

play09:37

it's an entirely separate version of the

play09:41

max function

play09:42

if we were to use the max function with

play09:45

float parameter types then once again

play09:48

the compiler would encounter this and it

play09:50

would generate a second version of our

play09:52

max function

play09:53

except where t appears we would now have

play09:56

float which would replace all of those

play09:59

occurrences of

play10:02

t generic sub-programs are also

play10:06

supported in java 5 in which case we

play10:10

refer to these sub-programs as generic

play10:13

methods now it's important to understand

play10:16

that generics in java differ from

play10:19

template functions in c plus and we'll

play10:22

spend the next few slides discussing

play10:25

these differences

play10:26

so the first and simplest difference is

play10:28

that generic parameters in java must be

play10:32

classes

play10:33

and they are not allowed to be primitive

play10:36

data types such as int or float

play10:40

so over here we have an example of a

play10:43

generic method in java our method is

play10:46

called do it it is a static method which

play10:51

is defined to be public within the class

play10:53

it is defined for and we can see that we

play10:56

have specified a generic type t within

play11:00

these angled brackets over here we've

play11:02

also specified that as a parameter the

play11:06

do it method receives a list which is an

play11:11

array that contains t

play11:13

values

play11:14

we also have a return type for our do it

play11:17

method which is also of type t

play11:22

so what this thing means is we can

play11:25

legally use the doit method as we can

play11:28

see over here so here we are calling our

play11:30

do-it method we have to specify in java

play11:33

in angled brackets what the generic type

play11:37

is in this case we've specified that

play11:39

it's a string

play11:41

now this is legal because string is an

play11:45

object it isn't a primitive type like an

play11:48

int or a float

play11:50

we then pass through as a parameter to

play11:53

the do it method my list which we can

play11:56

see has been specified up here so my

play11:58

list is an array that contains string

play12:02

objects once again our generic type is

play12:06

string and then we've simply specified

play12:08

that this is a new string with space

play12:10

allocated 14 string objects

play12:17

so let's look at how generic methods in

play12:20

java actually work behind the scenes

play12:23

once again we'll assume our generic do

play12:26

it method as well as this call to the do

play12:30

it method

play12:31

now what's very important to understand

play12:33

is that in java generic methods are

play12:36

instantiated only once and this happens

play12:39

at run time so this is different to c

play12:42

plus

play12:43

where a generic template function has a

play12:46

different version generated for every

play12:48

type that it is used with

play12:50

and these different versions of the

play12:53

generic template function are generated

play12:56

at compile time instead there is only

play12:59

one version of a generic method and this

play13:02

is a runtime construct so what this

play13:04

means in terms of our example over here

play13:07

is that there is only one occurrence of

play13:10

the do it method and this is a runtime

play13:14

construct

play13:16

now what actually happens is that

play13:17

instances of the object class are used

play13:20

wherever the generic type t appears

play13:24

so in our do it method we see that the

play13:27

parameter is an array that contains

play13:31

t

play13:31

objects

play13:33

actually behind the scenes what happens

play13:35

is the duet method receives an array

play13:37

that contains instances of the object

play13:40

class

play13:41

similarly the do-it method returns a

play13:44

generic type t but what actually happens

play13:47

behind the scenes is that it returns an

play13:51

object

play13:53

now

play13:53

the do it method then can in fact

play13:56

receive and return any particular object

play14:00

and this is because objects inherit from

play14:04

the object class in java

play14:06

so in terms of our parameter we see that

play14:09

we are receiving an array of objects

play14:12

what this means is that the do it method

play14:14

can receive an array of any particular

play14:17

object because all objects in java

play14:20

inherit from the object class

play14:23

in a similar fashion we can return any

play14:25

particular object because once again all

play14:29

objects in java inherit from the object

play14:32

class

play14:33

so this explains why generic types in

play14:36

java must be classes

play14:39

and they cannot be primitive types like

play14:42

ins or floats and so the reason for this

play14:45

is that we are actually storing and

play14:48

working with

play14:50

instances of the object class behind the

play14:52

scenes

play14:55

so the question that naturally arises

play14:58

then at this point is why don't we

play15:00

simply define our do-it method

play15:03

using objects as we saw in our previous

play15:07

example and the reason for this is that

play15:10

generics in java

play15:12

allow the compiler to automatically

play15:15

insert costs to the appropriate type and

play15:19

this improves the error detection of our

play15:21

code

play15:22

so in our example of the do it method

play15:26

over here the compiler will insert two

play15:28

costs for us if we are using the do-it

play15:32

method with the type of string

play15:36

so firstly it will cost the parameter

play15:39

which is this list over here and its

play15:42

type is an object array will

play15:44

automatically insert a cost that

play15:46

converts list into a string array

play15:50

it will also automatically insert a cost

play15:54

for the returned object to type string

play15:59

so what this means then is that if there

play16:01

is a type misuse then this will be

play16:04

picked up at compile time rather than at

play16:08

run time so let's say for example that

play16:10

somebody were to try to use the do it

play16:13

method but instead of then passing

play16:16

through an array of strings as in our

play16:19

example over here where we pass through

play16:21

my list which has the correct type we

play16:23

instead passed through an array of

play16:26

student objects

play16:28

now with this version of the do it

play16:30

method without the automatic costs

play16:33

inserted we would not get a compile time

play16:36

area because we are still passing

play16:38

through an array of objects which is

play16:40

correct it will only be inside the

play16:43

implementation of the duet method where

play16:45

we will then get a runtime error because

play16:48

we will be trying to retrieve student

play16:51

objects from this array and that of

play16:54

course will not work

play16:56

in a similar fashion if we attempt to

play16:59

for example return a student object from

play17:02

the do it method then this will also be

play17:04

picked up at compile time because of the

play17:07

automatic cost that has been inserted

play17:11

in our version with just objects without

play17:14

this cost automatically inserted we

play17:17

won't get that error picked up until

play17:20

runtime where the returned object is

play17:23

actually used and at that point the type

play17:26

mismatch is then detected

play17:28

so what's very important to understand

play17:30

then at this point is that generics in

play17:33

java are actually not a necessity and in

play17:35

fact earlier versions of java prior to

play17:38

version 5 didn't support generics

play17:41

generics simply include these additional

play17:44

costs which make our programming a lot

play17:46

safer and highlight errors much earlier

play17:49

than runtime where they would ordinarily

play17:52

be detected

play17:55

generics in java also provide a little

play17:57

bit of additional functionality that c

play18:00

plus doesn't provide so firstly we can

play18:03

restrict class ranges for generic

play18:05

parameters and that's exactly what we've

play18:07

done in this example over here

play18:09

so here once again we've got a do it

play18:12

method and this works with a generic

play18:15

type t and once again we can see that

play18:17

we've used t both in the parameter and

play18:20

the return for the do it method however

play18:23

additionally we have specified in the

play18:25

angled brackets that t

play18:27

explains comparable so what this means

play18:30

is that t must be a sub type of

play18:33

comparable which means that t must be a

play18:36

class that either inherits from a class

play18:39

called comparable or it implements an

play18:42

interface called comparable now in this

play18:44

particular example comparable is an

play18:47

interface that is provided by the java

play18:49

programming language itself

play18:54

now java 5 also allows for wild card

play18:58

types to be specified for generic

play19:00

parameters as we can see in this example

play19:03

over here

play19:04

so here we've specified a method called

play19:06

print collection that returns nothing

play19:09

however it receives a parameter called c

play19:13

which is a collection object now the

play19:16

collection class is a generic class that

play19:19

contains instances of a particular

play19:22

generic type so we've specified a

play19:25

question mark for this generic type in

play19:27

the angled brackets after the collection

play19:30

class name

play19:32

and this question mark means any object

play19:35

so what this means is that the print

play19:37

collection method can receive an

play19:39

instance of the collection class that

play19:42

contains objects of any particular class

play19:46

now it is also possible for us to

play19:48

restrict this wild card question mark

play19:51

symbol using the extends special word in

play19:54

which case we then restricted to inherit

play19:57

from or implement an interface that we

play20:01

have specified similar to what we saw on

play20:04

the previous slide

play20:07

finally c-sharp 2005 also supports

play20:11

generic sub-programs in the form of

play20:14

generic methods which are similar to the

play20:16

generic methods that we saw in java 5.

play20:20

there are two main differences firstly c

play20:23

sharp does not support wild cards the

play20:26

way that java does

play20:27

and secondly if the c sharp compiler can

play20:31

infer the unspecified type then the

play20:34

actual type parameters in the call can

play20:36

be emitted so we see that in this

play20:38

example over here

play20:40

here we have specified a generic method

play20:43

called do it we specify that there is a

play20:46

single generic type namely t

play20:49

and we've specified that the type of the

play20:51

parameter for doit is t

play20:54

and also the return type for the do it

play20:57

method is t

play21:00

now here we have two calls to the doit

play21:03

method the first one we can see over

play21:05

here

play21:06

since through an integer parameter which

play21:09

is 17 and we can also see that the

play21:11

return of the doit method is assigned to

play21:15

an integer variable called myint

play21:18

so what this means then is that the

play21:20

compiler will automatically infer that

play21:22

the generic type for this call should be

play21:26

an int

play21:27

in a similar fashion here we have a

play21:28

second call to the doit method here

play21:31

we're passing through a string

play21:33

apples as the parameter and also the

play21:36

return of the call to do it is assigned

play21:38

to a string variable called mystr

play21:42

so in this case also the c-sharp

play21:45

compiler will determine that the generic

play21:47

type should be string

play21:49

now in java we always have to specify

play21:52

the generic type in the call so for

play21:55

example with the second call we would

play21:57

have to place angled brackets after the

play22:00

do it method name and specify that the

play22:03

type is string for this particular call

play22:10

next we'll look at three design issues

play22:12

that apply specifically to functions

play22:16

recall that a function is a sub-program

play22:19

that produces a result by means of a

play22:21

return

play22:23

so the first of these design issues

play22:25

relates to where the side effects are

play22:28

allowed for functions and we've already

play22:30

spoken about this in quite a lot of

play22:32

detail in chapter 15 so i won't repeat

play22:35

that discussion here

play22:37

however what does bear mentioning is

play22:40

that to reduce side effects we generally

play22:43

speaking want parameters to be in mode

play22:45

only and some programming languages such

play22:48

as ada enforce this however most

play22:51

programming languages do not

play22:56

the second design issue specific to

play22:58

functions is how many values can be

play23:01

returned by a function

play23:04

so most programming languages restrict

play23:06

the number of returned values to only a

play23:10

single value however ruby and lua are

play23:13

two notable exceptions to this rule

play23:16

so ruby methods allow for multiple

play23:19

values to be returned and we see that in

play23:21

this example over here here we have a

play23:23

method called multiple values and we can

play23:26

see that we are returning several values

play23:30

where the values are separated by means

play23:32

of commas now what actually happens

play23:35

behind the scenes is that ruby will

play23:37

package these values together within an

play23:39

array which will be returned now of

play23:42

course we can use arrays to simulate

play23:45

multiple return values in any

play23:47

programming language that supports

play23:49

arrays

play23:51

now lua functions also allow for

play23:53

multiple return values and these work by

play23:56

means of multiple target assignments

play23:59

which we discussed in chapter 7 and you

play24:02

can review that chapter in order to see

play24:04

a few code examples of how these

play24:06

multiple return values would work in

play24:09

practice

play24:12

the final design issue specific to

play24:14

functions relates to what types of

play24:17

return values are allowed for functions

play24:21

now different programming languages have

play24:23

different approaches to which return

play24:26

types are allowed and so we'll look at a

play24:28

couple of practical examples on this

play24:31

slide

play24:32

so c and c plus plus functions allow any

play24:36

type to be returned except for arrays

play24:39

and functions however functions in these

play24:43

languages can return pointers rather

play24:46

than arrays

play24:47

and function pointers rather than

play24:49

functions themselves

play24:51

c plus plus of course also allows user

play24:54

defined types to be returned by

play24:57

functions

play24:58

ada sub programs can return any

play25:01

particular type however in ada sub

play25:04

programs are not considered to be types

play25:06

and therefore ada sub programs can't

play25:09

return sub programs

play25:11

java and c sharp methods can both return

play25:14

any type however in both of these

play25:16

languages methods are not considered

play25:19

types and therefore methods cannot

play25:21

return methods within these two

play25:24

languages

play25:25

and then finally in python ruby and lua

play25:29

any class can be returned and methods

play25:32

are also considered to be first class

play25:34

objects so therefore methods can also be

play25:38

returned within these programming

play25:40

languages

play25:44

some but not all programming languages

play25:47

support user-defined overloaded

play25:49

operators and in these languages the

play25:52

programmer can specify their own

play25:55

implementations

play25:57

for existing operators within the

play26:00

programming languages but for new types

play26:03

so user-defined overloaded operators are

play26:06

supported in ada c plus python and ruby

play26:10

and over here we have an example of a

play26:12

user-defined edition operator that is

play26:15

specified in python we're assuming that

play26:18

this operator is implemented for the

play26:21

complex class in python which is a class

play26:24

that represents complex numbers complex

play26:28

numbers consist of a real part and an

play26:31

imaginary part

play26:32

so here we are defining a subprogram

play26:36

called add and this is a special

play26:38

reserved sub program name

play26:41

that indicates we are defining an

play26:44

addition operator

play26:45

we have two parameters for this sub

play26:48

program

play26:49

self is the left operand and second is

play26:53

the right operand for the operator and

play26:56

both self and second have the type of

play26:59

complex

play27:01

so then we have the body of our user

play27:03

defined overloaded edition operator and

play27:06

this creates a new object of type

play27:09

complex and it sets the real part to the

play27:13

addition of the left and right operands

play27:16

real parts and the imaginary part of the

play27:20

new complex

play27:22

object to the sum of the imaginary parts

play27:26

for the left and right operands

play27:29

so this operator then is defined for two

play27:32

complex objects and if we assume that x

play27:35

and y are two complex objects then these

play27:39

are the two ways in which this operator

play27:42

can be used so firstly we can explicitly

play27:45

call this add subprogram sending through

play27:48

as a single parameter the right operand

play27:52

and we specify the left operand as the

play27:54

object that the add method is called on

play27:58

alternatively we can simply use the

play28:00

operator notation where we use the plus

play28:03

symbol in order to add x and y to one

play28:07

another

play28:10

next we'll take a look at closures and

play28:13

closures are very important for test and

play28:16

exam purposes

play28:17

so over here we have a simple example

play28:19

that illustrates how closures work in

play28:22

javascript

play28:24

here we have a function called make

play28:26

adder and as you can see make adder

play28:28

receives a single parameter

play28:30

namely x

play28:32

now the make adder function creates a

play28:35

new function which is an anonymous

play28:38

function because it doesn't have a name

play28:40

associated with it

play28:42

so make adder creates this function and

play28:45

then returns it so you can think of the

play28:48

make adder function as a factory that

play28:51

creates new functions

play28:54

now this anonymous function that is

play28:57

created it receives a single numeric

play29:00

parameter which is called y

play29:02

and it returns then y plus another value

play29:06

which is specified by means of x which

play29:09

is the parameter that has been sent

play29:11

through to make adder so essentially

play29:14

make adder then constructs functions but

play29:17

it can parameterize those functions

play29:20

depending on inputs sent in to make

play29:23

adder by means of its parameter

play29:28

in order for a closure in javascript to

play29:30

be used we need to assign the anonymous

play29:34

function which is the closure to a

play29:36

variable so that's exactly what we do

play29:39

over here here we call make adder and we

play29:42

pass through a parameter of 10 to that

play29:46

so in other words x will then have a

play29:49

value of 10. what this means then is

play29:52

that we return a new anonymous function

play29:55

which is in our closure where x now has

play29:59

a value of 10. so this is the form of

play30:02

the function that will be returned we

play30:04

can see that x's value is 10 over here

play30:08

the function receives a single parameter

play30:11

y and we return tin plus y

play30:15

that function is then assigned to the

play30:17

variable add team

play30:20

in a similar fashion here we call make

play30:22

adder with a parameter value of five

play30:25

so in this case then x's value that is

play30:28

sent through is five so this is then the

play30:31

form of our anonymous function that gets

play30:34

returned by make adder we are receiving

play30:37

a single parameter y for this function

play30:40

and we are returning five plus y

play30:43

this anonymous function is then assigned

play30:46

to the variable add five so what we can

play30:49

now do is we can call these anonymous

play30:52

functions by means of the variables add

play30:55

10 and add 5 and that's exactly what we

play30:58

do at this point and this point within

play31:01

our program

play31:03

so at this stage here we are now calling

play31:06

an anonymous function that has been

play31:07

returned by make added through the

play31:09

variable at 10

play31:11

and this will then add 10 and whatever

play31:14

parameter value has been seen through

play31:16

which in this case is 20 and therefore

play31:19

the result returned by that call will be

play31:22

30. in a similar fashion over here we

play31:26

are calling add 5 which is the variable

play31:29

referring to our anonymous function

play31:32

and we are sending through a parameter

play31:35

value of 20 to that that will then add 5

play31:39

and 20 and return a value of 25.

play31:47

now let's for the purposes of our

play31:49

example assume that we call make adder

play31:53

with a parameter value of 10 but instead

play31:56

of sending through a literal value of 10

play31:59

as we do in this example we instead have

play32:02

a variable with a value of 10 which we

play32:04

then pass through as the parameter to

play32:08

make adder

play32:09

now what's important to understand is

play32:12

that the closure that is returned by

play32:14

make adder is assigned to a variable and

play32:17

this variable can be passed around it

play32:19

can be synced to another sub-program for

play32:22

example and it could be executed at any

play32:26

particular time and what may happen is

play32:29

that the variable that we pass through

play32:32

as the parameter to make adder may have

play32:34

gone out of scope by the stage that add

play32:38

team is called

play32:40

so

play32:41

what this then means is that javascript

play32:45

must maintain the storage for whichever

play32:48

variable has been passed through to make

play32:51

adder and it must maintain this for the

play32:54

entire program execution and the reason

play32:57

for this is that the closure can be

play33:00

called at any point through the course

play33:03

of program execution we can't be sure

play33:06

when it will actually be called so what

play33:09

this means is that any variable passed

play33:11

to make adder must then exist from that

play33:15

point on through the course of the

play33:16

entire execution of the program until

play33:19

the program eventually terminates and

play33:22

what we would then say is that this

play33:24

variable has unlimited extent

play33:29

the final topic that we'll get to in

play33:32

this chapter is co-routines and

play33:35

co-routines are also very important for

play33:38

test and exam purposes and are

play33:40

relatively easy to understand so i

play33:42

recommend paying some attention to them

play33:46

so a co routine then is a sub program

play33:49

with multiple entry points and the

play33:51

co-routine itself controls these entry

play33:55

points

play33:56

coroutines are directly supported within

play33:59

lua but not many other programming

play34:02

languages

play34:03

coroutines are sometimes also referred

play34:06

to as metric control mechanisms and this

play34:09

is because the caller and the called

play34:12

co-routines exist on a more equal basis

play34:15

than what we see with regular

play34:17

sub-programs where there's a definite

play34:19

hierarchical relationship between the

play34:22

caller and the called sub program

play34:27

now the method for calling a co routine

play34:30

is referred to as a resume and a resume

play34:34

does one of two things depending on when

play34:37

it is called so the first time that a

play34:40

resume is called for a co routine it

play34:43

begins execution at the beginning of

play34:45

that co routine

play34:47

then if we call a resume after

play34:50

the first time that it has been executed

play34:53

it will then pause the execution of the

play34:55

co-routine that is executing the resume

play34:58

and it will begin execution after the

play35:01

last executed statement for the

play35:03

co-routine that is being resumed

play35:06

so what this thing means is we can have

play35:09

cycles set up where co-routines can

play35:11

resume one another forever

play35:14

and this allows then a kind of a

play35:17

quasi-concurrent execution of program

play35:19

units where the execution is interleaved

play35:22

but it is not overlapped

play35:25

so

play35:26

co-routines are perfect for simulation

play35:29

style software for example if we are

play35:32

simulating a traffic light intersection

play35:36

so we might then have one subroutine

play35:39

that operates for a pair of traffic

play35:42

lights facing one another and then a

play35:44

second subroutine that operates for the

play35:47

pair of traffic lights at right angles

play35:49

to the first pair

play35:51

so what would happen then is as the

play35:54

first pair of traffic lights would

play35:56

transition to red then they would call a

play35:59

resume on the co routine dealing with

play36:01

the set of traffic lights at right

play36:03

angles which would then start up and

play36:05

begin executing from where they last

play36:08

left off therefore turning those traffic

play36:10

lights green and then cycling through to

play36:12

red again at which point a resume would

play36:15

be called for the first pair of traffic

play36:17

lights and so resumes can then be passed

play36:20

back and forth between these two

play36:22

co-routines and continuously control can

play36:26

then be hand handed from one to the

play36:28

other and back again we'll look at some

play36:31

examples of how this would work in

play36:33

practice

play36:34

in the next three slides

play36:39

so here we have a simple example of two

play36:42

co-routines that resume one another

play36:45

we assume that our first co-routine is

play36:47

called a and our second co-routine is

play36:50

called b

play36:52

we then have a master which you can

play36:54

think of as a main

play36:57

function

play36:58

and this then calls a resume on

play37:01

co routine a so this begins execution at

play37:04

the top of a and execution will continue

play37:07

until we reach this resume for b

play37:10

now there hasn't been a resume that has

play37:13

been called for co routine b yet so at

play37:16

this point control then moves up to the

play37:18

top of co routine b and we execute then

play37:21

a series of statements until we get to

play37:24

this next resume which is then 4a so at

play37:27

this point control then passes back to a

play37:30

but we continue executing from where we

play37:32

left off so in other words not the top

play37:35

of the a co routine but instead from

play37:37

this point on until we reach our next

play37:40

presume over here this thing passes

play37:43

control back to b

play37:44

at the point where we left off so we

play37:46

continue executing down from that point

play37:49

until we reach another resume which

play37:52

again passes control back to a where we

play37:55

left off we continue executing down and

play37:57

then finally reach this last resume over

play38:00

here which passes control back to b

play38:03

where we again continue where we left

play38:05

off and then finally co routine b will

play38:08

then terminate

play38:12

here we have a similar example to the

play38:14

one that we looked at on the previous

play38:16

slide this time however our first resume

play38:19

is for co-routine b

play38:22

so again we begin executing at the top

play38:24

of b we then reach a resume for co

play38:28

routine a at this point no resume has

play38:31

been called on curitin a yet so we pass

play38:34

control to the top of curitin a and

play38:37

begin executing from there down we then

play38:40

reach another regime four core routine b

play38:43

so at this point execution of curitin a

play38:45

is suspended we then move control over

play38:49

to co-routine b and continue executing

play38:51

from where we left off so we execute

play38:54

these statements reach another resume

play38:56

for co-routine a so again we suspend co

play38:59

routine b

play39:01

pass control back to co-routine a where

play39:04

we left off continue executing from

play39:07

there reach another resume for

play39:09

corrupting b pass control back to b and

play39:12

then finally terminate co routine b

play39:18

this final example illustrates how

play39:21

control can be passed back and forth

play39:23

indefinitely between two coroutines

play39:26

so in this example we once again have

play39:29

two co-routines a and b

play39:32

and our initial resume from our master

play39:35

sub program is for co-routine a

play39:38

now what's important to note here is

play39:40

that co-routines a and b both contain

play39:44

loops so the initial resume will begin

play39:46

execution at the top of co-routine a and

play39:49

will then enter our loop at which point

play39:52

we will then reach after a number of

play39:55

statements our first resume for

play39:58

co-routine b

play39:59

so this point control is passed to co

play40:02

routine b we begin executing at the top

play40:04

and we enter our loop execute a series

play40:07

of statements and then we reach a resume

play40:09

for a so this again passes control back

play40:12

to a and we then begin executing from

play40:15

the point where we left off we loop back

play40:18

again and then we get to our resume for

play40:21

b once more which then passes control

play40:24

back to b and we continue executing from

play40:28

the point where we left off loop back

play40:30

and then reach a resume for a

play40:33

so we continue back and forth in and we

play40:35

will continue forever passing control

play40:38

back and forth between co-routines a and

play40:41

b

play40:42

until eventually some sort of

play40:44

termination condition is reached

play40:47

all right so that concludes then our

play40:49

discussion on chapter nine we will be

play40:52

skipping over chapter 10 which deals

play40:54

with how sub programs are implemented

play40:58

and we will in the next lecture be

play40:59

moving on to chapter 11 where we will

play41:02

discuss abstract data types and

play41:05

encapsulation concepts

Rate This
β˜…
β˜…
β˜…
β˜…
β˜…

5.0 / 5 (0 votes)

Related Tags
Sub-ProgramsOverloadingTemplatesGenericsPolymorphismC++JavaAdaDesign IssuesUser-Defined OperatorsClosuresCoroutines