29
More High-Level Concepts various languages…

Various languages…. Union Types Ada – compare to classes Coroutines Nested methods Lexical (static) vs. Dynamic Scope Referencing Environments

Embed Size (px)

Citation preview

Ruby

More High-Level Conceptsvarious languages Language ConceptsUnion TypesAda compare to classesCoroutinesNested methodsLexical (static) vs. Dynamic ScopeReferencing EnvironmentsSome examples from Clojure and Ruby

Unions TypesA union is a type whose variables are allowed to store different type values at different times during executionExample: flex/bison. Lexer needs to pass values to the parser. Flex/Bison (lex/yacc) uses a memory location that both programs know. BUT, value passed may be string, int, float, etc.Use a UNION to handle.

3C Unionunion flexType { int intEl; float floatEl; } el1;float x;int y;...el1.intEl = 27;y = el1.intEl;x = el1.floatEl; // nonsenseIs this the same as Rubys dynamic types? Why/why not?4Discriminated vs. Free UnionsFortran, C, and C++ provide union constructs in which there is no language support for type checking; the union in these languages is called free unionType checking of unions require that each union include a type indicator called a discriminantSupported by Ada

5Ada Union Typestype Shape is (Circle, Triangle, Rectangle);type Colors is (Red, Green, Blue);type Figure (Form: Shape) is recordFilled: Boolean;Color: Colors;case Form iswhen Circle => Diameter: Float;when Triangle =>Leftside, Rightside: Integer;Angle: Float;when Rectangle => Side1, Side2: Integer;end case;end record;6Ada Union Type IllustratedA discriminated union of three shape variables

7Evaluation of UnionsPotentially unsafe constructDo not allow type checkingJava and C# do not support unionsReflective of growing concerns for safety in programming languagehttp://stackoverflow.com/questions/5653678/union-types-and-intersection-types8CoroutinesA coroutine is a subprogram that has multiple entries and controls them itself (maintain status)Also called symmetric control: caller and called coroutines are on a more equal basisA coroutine call is named a resumeThe first resume of a coroutine is to its beginning, but subsequent calls enter at the point just after the last executed statement in the coroutineCoroutines repeatedly resume each other, possibly foreverCoroutines provide quasi-concurrent execution of program units (the coroutines); their execution is interleaved, but not overlapped

Information from: Programming Languages, Sebesta9Copyright 2006 Addison-Wesley. All rights reserved.Coroutines Illustrated: Possible Execution Controls

10Copyright 2006 Addison-Wesley. All rights reserved.Coroutines Illustrated: Possible Execution Controls

11Copyright 2006 Addison-Wesley. All rights reserved.Coroutines Illustrated: Possible Execution Controls with Loops

12Coroutines (cont)Coroutines originated as an assembly-language techniqueSupported in some high-level languages, Simula and Modula-2 being two early examples.Coroutines are well-suited for implementing more familiar program components such as cooperative tasks, iterators, infinite lists, and pipes (per Wikipedia)13Nested SubprogramsNot allowed in C and descendantsAllowed in Algol 68, Pascal, AdaMore recently included in JavaScript and Python

What about Ruby? Not really (interesting example coming up)14Variable Attributes: ScopeThe scope of a variable is the range of statements over which it is visibleThe nonlocal variables of a program unit are those that are visible but not declared thereStatic scoping: Algol, Pascal, C-type, RubyDynamic scoping: BashProgrammer choice: Perl, Lisp151-16Static Scope (aka lexical scope)procedure Big isX : Integer; procedure Sub1 is X : Integer; begin ... end; procedure Sub2 is begin ..X.. end;begin // Big ... end;

Reference to X in Sub2 refers to X in static parent Big. The X in Sub1 is not a static ancestor of Sub2.Scope of Sub1Scope of Sub2Scope of BigC & C++ do not allow nested procedures. Nor does Java. Inner classes may accomplish some of same goalsBased on program textSearch declarations, first locally, then in increasingly larger enclosing scopes

Dont confuse static scope with static lifetime!What languages use static scope?Pascal, Ada, ML, Haskell16Scope (continued)Variables can be hidden from a unit by having a "closer" variable with the same nameint count;while (...) { int count; ...}illegal in Java and C#, legal in C and C++C++ and Ada allow access to these "hidden" variablesIn Ada: unit.nameIn C++: class_name::name, ::name for globalNotice that blocks also create static scopesScope resolution operator17Dynamic Scope

Based on calling sequences of program units, not their textual layout temporal versus spatialReferences to variables are connected to declarations by searching back through the chain of subprogram calls that forced execution to this point. Must be determined at runtime.18Example from Sebesta: Principles of Programming LanguagesScope ExampleMAINdeclaration of x SUB1 declaration of x ... call SUB2 ... SUB2 ... reference to x ... ... main body MAIN calls SUB1SUB1 calls SUB2SUB2 uses x ---- declared in SUB1

MAIN calls SUB2SUB2 uses x----- declared in MAIN

Static scoping Reference to x in SUB2 is to MAIN's xDynamic scoping Reference to x depends on call sequence19Quick Examplevar y = "global"; function print-y() { print(y); } function test-scope() { var y = "local"; print-y(); } test-scope(); // static languages print "global" // dynamic languages print "local" print-y(); // all languages should print "global" dynamic example would work in Logo, bash, emacs lisp (but syntax would need to be altered to match the language, of course)Referencing EnvironmentsThe referencing environment of a statement is the collection of all names that are visible in the statementIn a static-scoped languagelocal variables plusall of the visible variables in all of the enclosing scopes In a dynamic-scoped languagelocal variables plus all visible variables in all active subprogramsReferencing Environment concept is important because data structures must be created to provide access to all nonlocal variables Future topic: closures21Example from Sebesta: Principles of Programming LanguagesReferencing Environments Static Exampleprocedure Example is A, B : Integer; ... procedure Sub1 is X, Y : Integer; begin #a ... end; procedure Sub2 is X : Integer; ... procedure Sub3 is X : Integer; begin - #b end; begin - #c end; // Sub2begin - ... #dend. Point a env: X and Y of Sub1, A and B of ExamplePoint b env: X of Sub3 (X of Sub2 is hidden), A and B of Example

Point c env: X of Sub2, A and B of Example

Point d env: A and B of Example22Referencing Environments Dynamic Examplevoid sub1() { int a, b; #X }void sub2() { int b, c; #Y sub1;}int main(){ int c, d; #Z sub2();}Assume main calls sub2, which calls sub1:Point #X env: a and b of sub1c of sub2d of main (c of main and b of sub2 are hidden)Point #Y env: b and c of sub2d of main (c of main hidden)Point #Z env: c and d of mainWell do a scoping exerciseExample from Sebesta: Principles of Programming Languages23Dynamic Scoping: ClojureUses the binding macroSuggested usesdebug function calls by dynamically overriding that function to print every time it gets calledTheclojure/java.jdbclibrary uses a dynamic var *db* so that you don't have to pass in a database connection to every function call. You can just use the with-connection macro to bind *db* to the database you want to use, and then perform any database queries within the body of the macro.It allows you to mock functions that have side-effects to make them more unit-testable.From: http://blog.rjmetrics.com/lexical-vs-dynamic-scope-in-clojure/More Clojure examplesA very useful application of dynamic scoping is forpassing contextual parameters without having to add new parameters explicitly to every function in a call stack(defn do-stuff [] (do-other-stuff) (print "stuff done!")) (binding [*out* my-debug-output-writer] (do-stuff))

From: http://programmers.stackexchange.com/questions/103164/when-would-dynamic-scoping-be-usefulWhat about Ruby?Ruby allows access to current variable bindings via Kernel#bindingA Ruby exampleclass Largeco class Person def hello # notice definitions inside hello def hi "hello" end def bye "goodbye" end #notice call to hi hi end # of hello definition def hi "hi" end def bye "bye-bye" end end # end Person classend # end Largeco classputs "Scott and Mark are casual"scott = Largeco::Person.newmark = Largeco::Person.newputs "Scott says: #{scott.hi}"puts "Mark says: #{mark.hi}"puts "Scott says: #{scott.bye}"puts "Mark says: #{mark.bye}"puts "\nBUT Chris is formal, everyone must respond in kind"chris = Largeco::Person.newputs "Chris says: #{chris.hello}"puts "Scott says: #{scott.hi}"puts "Chris says: #{chris.bye}"puts "Scott says: #{scott.bye}"Example (not recommended) from https://gist.github.com/markmcspadden/1322598 Quick Ex: Trace this!Not really nested methodsdef test_outer( a, b ) def test_inner( a )puts "#{a} and #{b}" end

test_inner( a+b )end # test_outer

test_outer( 1, 2 )Result: b is undefinedhttp://www.justskins.com/forums/nested-methods-and-scope-198687.htmlAnother exampledef toggle

def toggle puts "subsequent" end

puts "first"end

toggletoggletoggleOutput:firstsubsequentsubsequent

Why?Explain to your partner why are these not nested methods?