@@ -32,7 +32,7 @@ basics from a C# programmer's point of view.
32
32
### Classes
33
33
34
34
The basic concept of classes is the same in Scala as in C#. A class
35
- bundles up a bunch of state (member fields) and hides it behind an
35
+ can contain state (member fields) and hides it behind an
36
36
interface (member methods). The syntax for declaring classes is just
37
37
like C#:
38
38
@@ -151,7 +151,7 @@ We'll see why this is important in a moment.
151
151
### Function Types
152
152
153
153
In C#, you can have variables that refer to functions instead of data.
154
- These variables have delegate types, such as * Predicate<T >` or
154
+ These variables have delegate types, such as ` Predicate<T> ` or
155
155
` Func<T, TResult> ` or ` KeyEventHandler ` or ` Action<T1, T2> ` .
156
156
157
157
Scala has the same concept, but the function types are built into the
@@ -164,9 +164,9 @@ Effectively, Scala gets rid of all those weird custom delegate types
164
164
like ` Predicate<T> ` and ` Comparer<T> ` and has a single family of
165
165
function types like the C# ` Func<...> ` family.
166
166
167
- What if you want to refer to a method that doesn 't have a return value?
168
- In C#, you can't write ` Func<T, void> ` because void isn't a valid
169
- type; you have to write ` Action<T> ` instead. But Scala doesn't have
167
+ Refering to methods that don 't have a return value in C# is not
168
+ possible with ` Func<T, void> ` , because void isn't a valid type.
169
+ It is necessary to write ` Action<T> ` instead. Scala doesn't have
170
170
different families of delegate types, it just has the built-in
171
171
function types. Fortunately, in Scala, ` Unit ` is a real type, so you
172
172
can write ` (Int) => Unit ` for a function which takes an integer
@@ -507,9 +507,9 @@ In C#, if you want to create a singleton object, you have to create a class,
507
507
then stop evildoers creating their own instances of that class, then create
508
508
and provide an instance of that class yourself.
509
509
510
- While this is hardly a Burma Railway of the programming craft, it does
511
- feel like pushing against the grain of the language. Nor is it great for
512
- maintainers, who have to be able to recognise a singleton by its pattern
510
+ While this is hardly a real-world issue, it does feel like pushing against
511
+ the grain of the language. Nor is it great for maintainers, who have to be
512
+ able to recognise a singleton by its pattern
513
513
(private constructor, public static readonly field, ...), or for clients,
514
514
who have to use a slightly clumsy multipart syntax to refer to the
515
515
singleton (e.g. ` Universe.Instance ` ).
@@ -538,76 +538,101 @@ example derive from classes. This is a nice way of creating special values
538
538
with custom behaviour: you don't need to create a whole new type, you just
539
539
define an instance and override methods in it:
540
540
541
- abstract class Cat {
542
- def humiliateSelf()
541
+ abstract class Planet {
542
+ def distanceFromEarth: BigInt
543
543
}
544
-
545
- object Slats extends Cat {
546
- def humiliateSelf() { savage(this.tail) }
544
+
545
+ object Earth extends Planet {
546
+ // We can implement the method with a constant value
547
+ val distanceFromEarth: BigInt = 0
547
548
}
548
549
549
- Obviously this is a frivolous example, but "special singletons" turn out to
550
+ Obviously this is a simple example, but "special singletons" turn out to
550
551
be an important part of the functional idiom, for example for bottoming out
551
552
recursion. * Scala by Example (PDF)* describes an implementation of a Set class
552
553
which is implemented as a tree-like structure ("left subset - member - right
553
554
subset"), and methods such as ` contains() ` work by recursing down to the
554
555
child sets. For this to work requires an ` EmptySet ` whose implementation
555
556
(state) and behaviour are quite different from non-empty sets -- e.g.
556
557
` contains() ` just returns ` false ` instead of trying to delegate to
557
- non-existent child sets. Since ` EmptySet ` is logically unique it is both
558
- simpler and more efficient to represent it as a singleton: i.e. to declare
559
- ` object EmptySet ` instead of ` class EmptySet ` .
558
+ non-existent child sets. Since ` EmptySet ` is logically unique and immutable
559
+ it is both simpler and more efficient to represent it as a singleton:
560
+ i.e. to declare ` object EmptySet ` instead of ` class EmptySet ` .
560
561
561
562
In fact the whole thing can become alarmingly deep: * Scala by Example*
562
563
also includes a description of ` Boolean ` as an ` abstract class ` , and
563
564
` True ` and ` False ` as singleton objects which extend ` Boolean ` and provide
564
565
appropriate implementations of the ` ifThenElse ` method.
565
566
566
- And fans of Giuseppe Peano should definitely check out the hypothetical
567
- implementation of ` Int ` ...
568
-
569
567
### Pass by Name
570
568
571
- > You're only on chapter 3 and you're already reduced to writing about
572
- > * calling conventions* ? You suck! Do another post about chimney sweeps
573
- > being hunted by jars of marmalade!"
574
-
575
- Silence, cur. Pass by name is not as other calling conventions are.
576
- Pass by name, especially in conjunction with some other rather
577
- theoretical-sounding Scala features, is your gateway to the wonderful
578
- world of language extensibility.
579
-
580
- #### What is Passing By Name?
581
-
582
- First, let's talk about what we mean by * calling convention* . A calling
583
- convention describes how stuff gets passed to a method by its caller.
584
- In the good old days, this used to mean exciting things like which
585
- arguments got passed in registers and who was responsible for resetting
586
- the stack pointer. Sadly, the days of being able to refer to "naked fun
587
- calls" are consigned to history: In modern managed environments, the
588
- runtime takes care of all this guff and the main distinction is pass
589
- data by value or by reference. (The situation on the CLR is slightly
590
- complicated by the need to differentiate passing values by value, values
591
- by reference, references by value and references by reference, but I'm
592
- not going to go into that because (a) it's irrelevant to the subject at
593
- hand and (b) that's
594
- [ Jon Skeet] ( http://www.yoda.arachsys.com/csharp/parameters.html ) 's turf
595
- and I don't want him to shank me. Again.)
596
-
597
- In * pass by value* , the called method gets a copy of whatever the caller
598
- passed in. Arguments passed by value therefore work like local variables
599
- that are initialised before the method runs: when you do anything to them,
600
- you're doing it to your own copy.
601
-
602
- In * pass by reference* , the called method gets a reference to the caller's
603
- value. When you do anything to a pass-by-reference argument, you're doing
604
- it to the caller's data.
605
-
606
- In * pass by name* , the called method gets... well, it's a bit messy to
607
- explain what the called method gets. But when the called method does
608
- anything to the argument, the argument gets evaluated and the "anything"
609
- is done to that. Crucially, evaluation happens every time the argument
610
- gets mentioned, and only when the argument gets mentioned.
569
+ A parameter passed by name is not evaluated when it is passed to a method.
570
+ It is evaluated -- and re-evaluated -- when the called method evaluates
571
+ the parameter; specifically when the called method requests the value of
572
+ the parameter by mentioning its name. This is the key to being able to
573
+ define your own control constructs.
574
+
575
+ The Java Virtual Machine - on which Scala runs - passes primitives as well
576
+ as references to objects by value.
577
+ Nonetheless, Scala enables passing arguments to a method by name.
578
+ (The Scala compiler invisibly "wraps" the argument as an anonymous function.)
579
+
580
+ Consider this piece of logging code:
581
+
582
+ def complicatedComputation = {
583
+ val result = ... // compute
584
+ log(isDebugEnabled(), printDebugMessage(result, "DEBUG " + result + ": "))
585
+ }
586
+
587
+ def printDebugMessage(result: Object, message: String) = {
588
+ ...
589
+ }
590
+
591
+ Ideally, the second argument should only be evaluated if the method
592
+ ` isDebugEnabled ` evaluates to true.
593
+
594
+ A naive implementation would compute the second argument eagerly and
595
+ cause potentially expensive computation of debug output even if
596
+ ` condition ` evaluated to ` false ` :
597
+
598
+ def log(condition: Boolean, action: Unit) {
599
+ if(condition) ... // Does not work as intended
600
+ }
601
+
602
+ An improved implementation might use a function for the second
603
+ parameter:
604
+
605
+ def log(condition: Boolean, body: () => Unit) {
606
+ if(condition) body
607
+ }
608
+
609
+ The C# implementation looks almost similar:
610
+
611
+ public void Log(bool condition, Action body)
612
+ {
613
+ if (condition)
614
+ {
615
+ body();
616
+ }
617
+ }
618
+
619
+ Both implementation share the issue that calling the method becomes
620
+ syntactically cumbersome:
621
+
622
+ // Scala
623
+ log(42==42, () => printDebugMessage(...))
624
+
625
+ // C#
626
+ Log(42==42, () => printDebugMessage(...))
627
+
628
+ Scala provides the possibility to not evaluate arguments eargely while
629
+ preservin a visually pleasing syntax at call site:
630
+
631
+ def log(condition: Boolean, body: => Unit) {
632
+ if(condition) body
633
+ }
634
+
635
+ log(42==42, printDebugMessage(...))
611
636
612
637
#### Not Just Another Calling Convention
613
638
@@ -647,6 +672,8 @@ argument at the call site, nor a reference to the argument at the call
647
672
site, but the actual expression that the caller wants it to use to generate
648
673
a value.
649
674
675
+ #### Short-Circuit Evaluation
676
+
650
677
Same goes for short-circuit evaluation. If you want short-circuit
651
678
evaluation in C#, your only hope if to get on the blower to Anders
652
679
Hejlsberg and persuade him to bake it into the language:
@@ -685,13 +712,6 @@ for the `condition1`, `condition2`, `ifTrue` and `ifFalse` arguments to be
685
712
evaluated by the callee if it needs them, not for the caller to evaluate
686
713
them before making the call.
687
714
688
- And that's what * pass by name* does. A parameter passed by name is not
689
- evaluated when it is passed to a method. It is evaluated -- and
690
- re-evaluated -- when the called method evaluates the parameter;
691
- specifically when the called method requests the value of the parameter by
692
- mentioning its name. This might sound weird and academic, but it's the key
693
- to being able to define your own control constructs.
694
-
695
715
#### Using Pass By Name in Scala
696
716
697
717
Let's see the custom while implementation again, this time with Scala
0 commit comments