COMPUTER SCIENCE 2P05 Programming Languages Subprograms Brock - - PowerPoint PPT Presentation

computer science 2p05
SMART_READER_LITE
LIVE PREVIEW

COMPUTER SCIENCE 2P05 Programming Languages Subprograms Brock - - PowerPoint PPT Presentation

COMPUTER SCIENCE 2P05 Programming Languages Subprograms Brock University Brock University (Subprograms) Programming Languages 1 / 38 Subprograms (And control structures) Weve had plenty of experience with procedural abstraction by now,


slide-1
SLIDE 1

COMPUTER SCIENCE 2P05

Programming Languages Subprograms

Brock University

Brock University (Subprograms) Programming Languages 1 / 38

slide-2
SLIDE 2

Subprograms

(And control structures)

We’ve had plenty of experience with procedural abstraction by now, but it wouldn’t hurt to expand upon that a bit. But before we get to that, we might want to briefly revisit our various control strutures: anything that controls the execution sequence (e.g. branching, conditionals, etc.). Simply subdividing instructions up into blocks isn’t really adequate for most well-defined solutions; we need to be able to selectively choose which blocks to employ for given data

Brock University (Subprograms) Programming Languages 2 / 38

slide-3
SLIDE 3

Conditionals

If we feel like talking about this, then we should

Many of you have already taken 2P12, so you might already be familiar with branch statements: The current value of the program counter is changed to a new address of code to execute

◮ (We aren’t going to make a distinction between branching and jumping

here)

The simplest branch is an unconditional branch, sometimes written as B, and has limited use There are typically other branches like BEQ (or BZ), BNE (or BNZ), etc., which will only change to a new location if some test passes. Otherwise, it simply proceeds to the next instruction within the code

Brock University (Subprograms) Programming Languages 3 / 38

slide-4
SLIDE 4

Conditionals?

How is this related?

What matters is what it’s performing that test on. e.g. if you’ve just performed a test on a value in a register (or accumulator), then there may be condition codes still set from that (or, of course, you might be directly comparing them) For an if statement, you might (might!) perform an operation on the value in which you’re interested, and then follow that with a branch statement to not enter the condition’s block

◮ i.e. you might effectively ‘flip the question’ to see if you should skip

past the block’s contents

Brock University (Subprograms) Programming Languages 4 / 38

slide-5
SLIDE 5

Does this help with repetition?

How do we translate this to loops?

Loops end up only minimally different: while loops are only a minor modification of the conditional:

◮ Have a branch to decide whether or not to skip the block ◮ At the end of the block, have an unconditional branch to return back

to the top

do...while loops are actually even easier

◮ Outside of possible scoping rules, there might not even be a notion of

‘entering the loop’; just have a conditional branch at the end to return to the top

for loops are slightly more complicated, but not much when you consider how they work when you compile them in high-level languages

Brock University (Subprograms) Programming Languages 5 / 38

slide-6
SLIDE 6

What about GOTO?

No. But seriously, no. From a functional standpoint, they’re simple (create a label, and then later jump to that label), but they can introduce several problems:

◮ Readability can be seriously impaired, especially when it comes to

confirming which values have been initialized

◮ Consider try/catch/finally blocks. Think of the havoc you could

wreak through arbitrary jumps!

Brock University (Subprograms) Programming Languages 6 / 38

slide-7
SLIDE 7

Final thought about conditionals...

Are we familiar with the dangling else problem? Consider the following Java code: i f (A) i f (B) System . out . p r i n t l n (” neat ! ” ) ; e l s e System . out . p r i n t l n (” nay ! ” ) ; For what values of A and B will we see "neat"? What about "nay!"?

Brock University (Subprograms) Programming Languages 7 / 38

slide-8
SLIDE 8

Let’s switch things up a little, shall we?

We’re all familiar with Java’s switch statement. e.g.:

java . u t i l . Scanner i n=new java . u t i l . Scanner ( System . i n ) ; i n t value=i n . n e x t I n t ( ) ; switch ( value ) { case 1: System . out . p r i n t l n (”Number 1 ! ” ) ; case 2: System . out . p r i n t l n (” Twice as good ! ” ) ; break ; case 3: System . out . p r i n t l n (”A crowd ? ” ) ; break ; d e f a u l t : System . out . p r i n t l n (” Whatevs ” ) ; }

Let’s just briefly make sure we know how to trigger each of these cases.

Brock University (Subprograms) Programming Languages 8 / 38

slide-9
SLIDE 9

Switchy disclaimer

We probably already know this, but while C and C++ follow largely the same rules for switches, not every language does. (e.g. considering Ada: the break isn’t necessary, but the default case becomes mandatory) There’s also the issue of what types you allow the switch to operate

  • n

◮ Working on any discrete type is common ◮ Sometimes enumerated types might be an option as well ◮ Java eventually added String support

Does this give a hint as to how it might be implemented?

Brock University (Subprograms) Programming Languages 9 / 38

slide-10
SLIDE 10

Implemented?

What’s there to implement?

Let’s take some guesses. What method for ‘implementing’ a switch first comes to mind?

Brock University (Subprograms) Programming Languages 10 / 38

slide-11
SLIDE 11

Yes, implemented!

And not everyone does it the same!

For whatever you guessed, how do you think it’d hold up? How efficient is it? How many conditions would need to be evaluated if there were many

  • ptions?

As a hypothetical, suppose (in C) you had an array of 5 function pointers, and a number with a possible value of 0..4. What could you do with that?

Brock University (Subprograms) Programming Languages 11 / 38

slide-12
SLIDE 12

Multiple selection

(That’s the formal name, by the way)

We don’t want to resort to treating it like if/elsif/elsif/.../else if we can avoid it for computational reasons. Instead, we can create a branch table, or branch array An array can be possible when the options are all densely-packed, but something like a hash table is more appropriate for the general case This is why multiple selections normally rely on being well-defined values, rather than e.g. ranges:

◮ Could you (easily) resolve a range to a single entry in the table? Brock University (Subprograms) Programming Languages 12 / 38

slide-13
SLIDE 13

What about Python?

Do we have multiple selection?

We don’t have switch, but we have the tools to simulate something similar. Remember our dictionaries? Since functions are first-class objects, it’s trivial to stuff several into a dictionary, and then index the dictionary as normal (invoking the result with whatever parameters we want) This does raise the question of how to handle default cases... eh... can we look at a super-quick example?

Brock University (Subprograms) Programming Languages 13 / 38

slide-14
SLIDE 14

Clarification on functions as value/objects

Python (and javascript, etc.) functions are first-class objects, meaning they may be used like any other object or value. As such, they can be initialized, re-defined, assigned to variables, passed as parameters, etc. Even though C/C++ has function pointers, this is not the same thing! The actual code itself will be static in C/C++ We can’t redefine the primary name of the function in C/C++ When assigning to variables or passing as parameters, technically we’re creating a type for that signature, and using the address of the function as the value (We also can’t assign members the same way, etc.)

Brock University (Subprograms) Programming Languages 14 / 38

slide-15
SLIDE 15

Anonymous functions

And lambda functions

You’ve probably heard both of these phrases, and may not know the difference between them. Sometimes, a distinction isn’t made. But we will Both of these concern defining a block of code, that ostensibly receives arguments, to return a value, that may be treated as an object or expression. Let’s look at the idea in three languages: javascript, Java, and Python

Brock University (Subprograms) Programming Languages 15 / 38

slide-16
SLIDE 16

Anonymous functions in JavaScript

JavaScript actually has two versions of this! (Though they’re nearly identical) f = f u n c t i o n (a , b) { console . log ( ’ hi ’ ) ; r e t u r n a+b ; } ; We also have arrow functions: f = (a , b)=>{console . log ( ’ hi ’ ) ; r e t u r n a+b ; } ; The biggest difference: these don’t have the this keyword, which is sometimes a good thing.

Brock University (Subprograms) Programming Languages 16 / 38

slide-17
SLIDE 17

Anonymous/lambda functions in Java

Prior to Java 8, the closest you’d get was an anonymous class with a single function. For 8+, we hava lambda expressions. If we have an interface that only requires an implementation for a single function, why couldn’t we just provide that? We make use of the -> arrow

◮ If the right-hand size isn’t a single statement, we need braces

This assumes Java can tell what type it’s trying to coerce it into Example time? Example time. (btw:

https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html)

((Also: here)) (((Also, I’m slightly lying. Do we know what syntactic sugar is?)))

Brock University (Subprograms) Programming Languages 17 / 38

slide-18
SLIDE 18

Lambda functions in Python

Python’s lambda functions are simple to write, and limited in functionality. The syntax is simple: lambda v1[,v2,v3,...] : expression You can assign it to a variable, pass it as an argument, or even invoke it right away (though... why?) This’ll make more sense with examples, and... we probably need a couple.

Brock University (Subprograms) Programming Languages 18 / 38

slide-19
SLIDE 19

Anonymous/lambda functions

Why do we need them?

There are a few reasons one might want to use such a function. If you want to use a behaviour only once, why clutter your design with lots of extra objects/functions/etc?

◮ Like anonymous classes, this can also be useful for event processing ◮ Also possibly good for arbitrary queries, comparisons, etc.

Runtimes and language specifications are evolving to better facilitate parallel processing (silly example: see forEach and Spliterator for Iterable). Lambda functions tend to be idempotent, orthogonal, etc., so they’re well-suited for concurrency As we saw in Python, we can use it to create specialized versions of existing functions

◮ This is a theme you might run into for other languages, not to mention

programming paradigms

Brock University (Subprograms) Programming Languages 19 / 38

slide-20
SLIDE 20

If you found that interesting...

(Additional topics)

We can expand this idea into things like breaking up arbitrarily-complex functions into modified versions of reduced arities, to e.g. using only single parameters each. Actually, there are all sorts of fun things we can do with this. If this appeals to you, you might be interested in learning about currying and partial function applications (Though all that’s outside the scope of this course)

Brock University (Subprograms) Programming Languages 20 / 38

slide-21
SLIDE 21

Closures

When we bind data to a function, we usually call that a closure. Commonly, this relies on defining non-local variables within an enclosing scope and attaching them to a nested function, and/or relying on the ‘object’ nature of functions in a language. Wait... this sounds familiar... We’ve already seem a very basic form of a closure when we made a function to create new functions, tied to the outer function’s parameter

◮ We’ll be revisiting the concept in a fancy way in a week-ish

Btw, in addition to the global keyword, we have a similarly used nonlocal keyword for nearly the same thing.

Brock University (Subprograms) Programming Languages 21 / 38

slide-22
SLIDE 22

Repeating repetition gets repetitive...

We don’t want to repeat code. We get that already. It’s part of why we use procedural abstraction in the first place. But we should all remember an obvious case of repeated code we considered in first year, as well as how we cut down on it... right? There should be a pretty generic answer for this...

Brock University (Subprograms) Programming Languages 22 / 38

slide-23
SLIDE 23

Technique the first: just don’t write code

In something like C, we can... write code instead of code? Write text instead of code? One common preprocessor command is the #define

◮ e.g. #define PI 3 ◮ What it’s really doing is, prior to compilation, finding every instance of

PI and replacing it with 3

We can define other replacements (we call them macros) But, is it a good idea? Let’s find out that it isn’t! (spoiler?)

Brock University (Subprograms) Programming Languages 23 / 38

slide-24
SLIDE 24

So what does C++ do?

Let’s look at the simplest example for C++: #i n c l u d e <iostream > using namespace std ; template<typename Dealie > Dealie maximum( Dealie a , Dealie b) { r e t u r n b>a?b : a ; } i n t main () { cout <<(maximum<int >(3,5))<< endl ; cout< <max<f l o a t >(5.3 f , 2 . 9 f)<<endl ; }

Brock University (Subprograms) Programming Languages 24 / 38

slide-25
SLIDE 25

What about Python?

Python largely sidesteps the issue by not requiring types to be explicitly declared. e.g. a+b is legal, regardless of whether a and b are int or float Of course, if you do want to enforce a type, it can be a bit more tedious. If nothing else, don’t forget that Python has a type function.

Brock University (Subprograms) Programming Languages 25 / 38

slide-26
SLIDE 26

And Java?

We know this one. But let’s play along... First up, just because we mentioned type, if you didn’t know, Java has a similar operator: instanceof

◮ e.g. e instanceof Employee ◮ But that doesn’t help us here

Instead, we make use of generics (or parametric polymorphism)

◮ Which gives us such delightful terms as parametrized type, type

variable, type parameter, and type argument

◮ All of which we remember from first year

The basic idea is, instead of modifying specific methods/functions, we just create new objects that’ll use the types we want! ... .. right?

Brock University (Subprograms) Programming Languages 26 / 38

slide-27
SLIDE 27

Java Generics

Well, not quite. Actually, the generics really only matter at compile-time. What are the types by the time we get to runtime?

◮ That’s complicated ◮ Ostensibly, the type variables get replaced by Object (or a bounding

type; next week)

◮ This is known as type erasure

So then, what’s the benefit?

◮ Compile-time is when we need it the most! ⋆ Compare against what came before Java 5: just use Object for

everything! It’s super-safe!

⋆ That brief, compile-time carefulness is what affords us type safety Brock University (Subprograms) Programming Languages 27 / 38

slide-28
SLIDE 28

Parameters

Yeah, no segue for this one. How do we declare and use parameters? What’s really going on? This is not as uniform across languages as one might expect What we want to talk about are parameter transmission modes. In mode Out mode In/Out mode In theory, there are different possible implementations for each (chapter 9 in the book if you’re interested), but we’re going to stick to what’s commonly used in traditional languages.

Brock University (Subprograms) Programming Languages 28 / 38

slide-29
SLIDE 29

Quick blurb on parameters

(and how subprograms are called)

Recall that our subprograms will be called by allocating call frames (or activation records, or stack frames, etc.) onto the stack. Once we’re done with the invocation, we can deallocate the frame, and unwind the stack a bit. If we had anything to return, we can leave it on the top of the stack. For many languages, this leads to certain technical limitations, particularly regarding fixed memory sizes. Recall that we do also have the heap e.g. in Java, we might have a local variable on the stack to hold an

  • bject, but really it’s just a reference to an object that exists on the

heap

◮ That reference has a fixed size (e.g. 64bits), so we know how much

space it requires

Brock University (Subprograms) Programming Languages 29 / 38

slide-30
SLIDE 30

Input parameters

These are just the parameters you’ve always known and used. In the function/method header, you declare a parameter

◮ That parameter receives data (it acts as an input for the subprogram)

The common implementation is pass-by-value: the data itself is given to the function

◮ For a language like C++, giving a struct (or union, class, etc.) as

an argument copies it

◮ It’s easy to allocate suitably sized memory for a well-defined structure ◮ However, this introduces many problems ⋆ Can we think of a few? Brock University (Subprograms) Programming Languages 30 / 38

slide-31
SLIDE 31

InOut parameters

InOut (or InputOutput, or In/Out, etc.) parameters are for pushing data into a function, and then receiving data back into the original variable used as the argument (from a usage standpoint)s. There are a couple of implementations (e.g. pass-by-value-result, which copies into the parameter, and then copies the data back into the original context upon leaving the subprogram) The most common implementation is pass-by-reference

◮ We’ve discussed references before: two labels can share the same

actual location in memory

◮ If you want the function to receive data, and return the result, just let

it operate on the data directly!

It’s worth noting that there’s another reason to use pass-by-reference: to avoid that copying of data structures. For those cases, you might not want the parameter to behave like an InOut!

Brock University (Subprograms) Programming Languages 31 / 38

slide-32
SLIDE 32

Pass-by-reference

Let’s look at a quick example, just to ensure that we understand this. Once we understand that example fully, this leaves a question: which does Java use, pass-by-reference, or pass-by-value?

Brock University (Subprograms) Programming Languages 32 / 38

slide-33
SLIDE 33

Output parameters

Most languages don’t require an output parameter. The primary goal is typically to allow for multiple returns. Of course, InOut parameters can be used for this (subject to parameter listing/naming concerns) The common alternative in something like C is to pass in pointers, so the invoked function can dereference the pointer and fiddle about in memory In Java, it’s assumed we’ll organize data appropriately, so we can just return a collection In Python, we have multiple returns (using the built-in tuple) Ada does allow you to specify an Output parameter, but it’s honestly not a common concern.

Brock University (Subprograms) Programming Languages 33 / 38

slide-34
SLIDE 34

Speaking of parameters...

...

... ...

Brock University (Subprograms) Programming Languages 34 / 38

slide-35
SLIDE 35

Variadic parameters

Suppose I wanted a function that would tell me the highest value from amongst several values. I’m not sure how many parameters to include though, because the number

  • f values could change.

Perhaps I could use a data structure?

◮ Definitely, this is an option

Use default parameters to something like None?

◮ You’re still stuck with a specific upper-bound, plus it’d be a nightmare

to code

Just decide to not care how many parameters there are? Yeah, let’s do that! A variadic function is one with an undefined arity Not every language supports it, but it’s pretty common Example time?

Brock University (Subprograms) Programming Languages 35 / 38

slide-36
SLIDE 36

What was that asterisk for in the Python example?

Yeah... we can actually do some powerful things with parameters by automatically packing them up into tuples (or automatically unpacking them when calling). Similarly, you can use a double-asterisk to collect named parameters into a dictionary (commonly called kwargs: keyworded-arguments) Until/unless we have a specific example for using them, I’d prefer to put this off for now. However, they aren’t actually complicated if you’re interested in a quick read:

https://www.saltycrane.com/blog/2008/01/how-to-use-args-and-kwargs-in-python/

Brock University (Subprograms) Programming Languages 36 / 38

slide-37
SLIDE 37

Coroutining

Concurrency comes later, but there’s a related topic: Suppose I have two functions I want to operate largely in-pace with each other

◮ e.g. maybe we need to just check on something now and then ◮ The important point is we aren’t talking about function A that keeps

calling function B (which would imply constantly deallocating B’s call frames), but rather two behaviours with equal precedence

How could one do that? You could try using a bunch of GOTO statements In C, there’s a jump buffer library you can use, wherein you keep saving the state of the stack onto an intermediate buffer, and swap the contexts manually

◮ It’s exactly as easy as it sounds

In Python, perhaps we could use yield? I know, we’ll be talking about this later

Brock University (Subprograms) Programming Languages 37 / 38

slide-38
SLIDE 38

Questions?

Comments?

Anyone have a sudden urge to fight off the undead?

Brock University (Subprograms) Programming Languages 38 / 38