User Tools

Site Tools


at:tutorial:basic

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
Next revisionBoth sides next revision
at:tutorial:basic [2007/04/17 17:30] tvcutsemat:tutorial:basic [2009/06/05 15:32] – added tvcutsem
Line 1: Line 1:
-<note> +
-**This Tutorial is still under heavy construction!!** +
-</note>+
 ====== Functional and Imperative Programming ====== ====== Functional and Imperative Programming ======
    
Line 34: Line 32:
 </code> </code>
  
-<note>+<note important>
 When using the '':='' assignment operator, beware of the following syntactic annoyance: the expression ''a := 1'' denotes an assignment to the variable ''a'', while ''a:= 1'' is misunderstood by the parser as ''a: = 1'', which is the invocation of a keyworded message named ''a:''. Keyworded message sends will be explained later on in this chapter. Hence, as a general rule, don't forget to always put a space between the variable name and the '':='' operator. When using the '':='' assignment operator, beware of the following syntactic annoyance: the expression ''a := 1'' denotes an assignment to the variable ''a'', while ''a:= 1'' is misunderstood by the parser as ''a: = 1'', which is the invocation of a keyworded message named ''a:''. Keyworded message sends will be explained later on in this chapter. Hence, as a general rule, don't forget to always put a space between the variable name and the '':='' operator.
 </note> </note>
Line 176: Line 174:
 </code> </code>
  
-In that case, the //sum// function still accepts an arbitrary number of arguments as long as two arguments are supplied. //a// and //b// are considered as mandatory arguments of the argument list. +In that case, the //sum// function still accepts an arbitrary number of arguments as long as two arguments are supplied. //a// and //b// are considered as mandatory arguments of the argument list. 
 + 
 +The splice operator can also be used to transform a table into an argument list for a function, for example: 
 +<code> 
 +def args := [3,4,5]; 
 +> sum(1,2, @args); 
 +>> 15 
 +</code> 
 + 
 +One way to think about this is that the splice operator splices the ''args'' table into the table of actual arguments. The "rest" arguments do not necessarily need to be the last parameters, for example: 
 +<code> 
 +> sum(1,2,@args,6); 
 +>> 21 
 +</code> 
 + 
 +==== Optional Parameters ====
  
 A function can also declare optional arguments as shown below. Optional arguments can be omitted in a function call. If this is the case, the default expression provided in their definition is evaluated and passed as argument to the function instead. A function can also declare optional arguments as shown below. Optional arguments can be omitted in a function call. If this is the case, the default expression provided in their definition is evaluated and passed as argument to the function instead.
Line 204: Line 217:
 >def [get, set] := makeCell(42); >def [get, set] := makeCell(42);
 >>[<closure:getter>, <closure:setter>] >>[<closure:getter>, <closure:setter>]
 +>get();
 +>>42
 </code> </code>
  
Line 225: Line 240:
    def total := a + b;     def total := a + b; 
    foreach: { |el| total := total + el} in: rest; total     foreach: { |el| total := total + el} in: rest; total 
- }; sum(1,2,3)+ }; 
 +>><closure:lambda>  
 +>sum(1,2,3)
 >>6 >>6
 </code> </code>
Line 243: Line 260:
   def i := 0;   def i := 0;
   def mapped[tbl.length] {   def mapped[tbl.length] {
-    clo(tbl[i:=i+1])+    i := i+1
 +    clo( tbl[ i ] )
   };   };
 } }
Line 339: Line 357:
 >>true >>true
 </code> </code>
 +
  
 ==== Tables ==== ==== Tables ====
    
  
-We have already introduce how to define tables. Let us now focus on how to manipulate them with the native methods provided by the table object.+We have already introduced how to define tables. Let us now focus on how to manipulate them with the native methods provided by the table object.
 <code> <code>
 >[1,2,3].filter: {|e| e != 2 } >[1,2,3].filter: {|e| e != 2 }
Line 399: Line 418:
 >>1 >>1
 > def [i, j] := [1,3] > def [i, j] := [1,3]
->>>[1, 3]+>>[1, 3]
 >{i < j}.whileTrue: { system.println(i); i := i + 1 } >{i < j}.whileTrue: { system.println(i); i := i + 1 }
 1 1
Line 408: Line 427:
 Compound boolean expressions can be created by means of a boolean's ''and:'' and ''or:'' methods, which both take a zero-argument closure as argument. For example, ''false.and: { 1/0 }'' will return ''false''. The block is not applied because a logical //and// with ''false'' always fails. Compound boolean expressions can be created by means of a boolean's ''and:'' and ''or:'' methods, which both take a zero-argument closure as argument. For example, ''false.and: { 1/0 }'' will return ''false''. The block is not applied because a logical //and// with ''false'' always fails.
  
-===== Control Flow Structures =====+===== Control Flow Constructs =====
  
-Control flow structures are defined in the lexical root of AmbientTalk. The lexical root is an object containing globally visible native methods. We have already seen in the previous sections examples of usage of the foreach and if/then structures. The complete list of traditional control flow structures defined in AmbientTalk is shown below:+Control flow constructs are defined in the lexical root of AmbientTalk. The lexical root is an object containing globally visible native methods (i.e. it is the top-level environment). We have already seen in the previous sections examples of use of the foreach and if/then structures. list of traditional control flow structures defined in AmbientTalk is shown below:
 <code> <code>
-if: booleanCondition then: { consequent } +if: booleanCondition then: consequentClosure 
-if: booleanCondition then: { consequent } else: { alternative } +if: booleanCondition then: consequentClosure else: alternativeClosure 
-while: { condition } do: body } +while: conditionClosure do: body 
-foreach: { |v| body } in: table ] +foreach: iteratorClosure in: table 
-do: { body } if: condition +do: bodyClosure if: condition 
-do: { body } unless: condition+do: bodyClosure unless: condition
 </code> </code>
-An example of usage for some of these structures is shown below in the definition of the sort function.+ 
 +<note warn> 
 +Note that ''conditionClosure'' in the ''while:do:'' construct denotes a //closure// that should return a boolean value. It needs to be a closure because the code is evaluated repeatedly until the closure returns false. ''bodyClosure'', ''consequentClosure'', ''alternativeClosure'' all denote zero-argument closures. As a general rule, all code that needs to be delayed or executed repeatedly must be wrapped in a closure. 
 +</note> 
 + 
 +The above definitions in the lexical root of AmbientTalk are simply convenience functions for the methods defined on booleans and closures. For example, an if-statement can also be encoded as a message send, as in Smalltalk: ''boolean.ifTrue: {...} ifFalse: {...}''
 + 
 +An example of usage for some of the above structures is shown below in the definition of the sort function.
 <code> <code>
 >def sort(table, cmp := { |e1,e2| e1 < e2 }) { >def sort(table, cmp := { |e1,e2| e1 < e2 }) {
- def quickSort(table, low, high) { +  def quickSort(table, low, high) { 
-     def left := low; +    def left := low; 
-     def right := high; +    def right := high; 
-     def pivot := table[(left+right) /- 2]; +    def pivot := table[(left+right) /- 2]; 
-     def save := nil; +    def save := nil; 
-        while: { left <= right } do: { +    while: { left <= right } do: { 
-     while: { cmp(table[left], pivot) } do: {  +      while: { cmp(table[left], pivot) } do: {  
-                left := left + 1  +        left := left + 1  
-            }; +      }; 
-     while: { cmp(pivot, table[right]) } do: {  +      while: { cmp(pivot, table[right]) } do: {  
-                right := right - 1  +        right := right - 1  
-            }; +      }; 
-     if: (left <= right) then: { +      if: (left <= right) then: { 
-     // swap elements +        // swap elements 
-     save := table[left]; +        save := table[left]; 
- table[left] := table[right]; +        table[left] := table[right]; 
- table[right] := save; +        table[right] := save; 
- left := left + 1; +        left := left + 1; 
- right := right - 1; +        right := right - 1; 
-     }; +      }; 
-    }; +    }; 
-    if: (low<right) then: { quickSort(table,low,right) }; +    if: (low<right) then: { quickSort(table,low,right) }; 
-    if: (high>left) then: { quickSort(table,left,high) }; +    if: (high>left) then: { quickSort(table,left,high) }; 
-    table; +    table; 
-   }; +  }; 
-   quickSort(table, 1, table.getLength()); +  quickSort(table, 1, table.length); 
- };+};
 >><closure:sort> >><closure:sort>
 >sort([2,37,6,4,5,8]) >sort([2,37,6,4,5,8])
 >>[2, 4, 5, 6, 8, 37] >>[2, 4, 5, 6, 8, 37]
 </code> </code>
 +
 +AmbientTalk has no ''return'' statement. To achieve a similar jump in the control flow, see the section on [[:at:tutorial:modular#escaping_continuations|escaping continuations]].
at/tutorial/basic.txt · Last modified: 2020/02/09 22:05 by elisag