8000 First bunch of fixes, mostly style. · soc-mirror/scala.github.com@3c4ced7 · GitHub
[go: up one dir, main page]

Skip to content

Commit 3c4ced7

Browse files
committed
First bunch of fixes, mostly style.
1 parent 31f558d commit 3c4ced7

File tree

1 file changed

+87
-67
lines changed

1 file changed

+87
-67
lines changed

tutorials/scala-for-csharp-programmers.md

Lines changed: 87 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ basics from a C# programmer's point of view.
3232
### Classes
3333

3434
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
3636
interface (member methods). The syntax for declaring classes is just
3737
like C#:
3838

@@ -151,7 +151,7 @@ We'll see why this is important in a moment.
151151
### Function Types
152152

153153
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
155155
`Func<T, TResult>` or `KeyEventHandler` or `Action<T1, T2>`.
156156

157157
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
164164
like `Predicate<T>` and `Comparer<T>` and has a single family of
165165
function types like the C# `Func<...>` family.
166166

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
170170
different families of delegate types, it just has the built-in
171171
function types. Fortunately, in Scala, `Unit` is a real type, so you
172172
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,
507507
then stop evildoers creating their own instances of that class, then create
508508
and provide an instance of that class yourself.
509509

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
513513
(private constructor, public static readonly field, ...), or for clients,
514514
who have to use a slightly clumsy multipart syntax to refer to the
515515
singleton (e.g. `Universe.Instance`).
@@ -538,76 +538,101 @@ example derive from classes. This is a nice way of creating special values
538538
with custom behaviour: you don't need to create a whole new type, you just
539539
define an instance and override methods in it:
540540

541-
abstract class Cat {
542-
def humiliateSelf()
541+
abstract class Planet {
542+
def distanceFromEarth: BigInt
543543
}
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
547548
}
548549

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
550551
be an important part of the functional idiom, for example for bottoming out
551552
recursion. *Scala by Example (PDF)* describes an implementation of a Set class
552553
which is implemented as a tree-like structure ("left subset - member - right
553554
subset"), and methods such as `contains()` work by recursing down to the
554555
child sets. For this to work requires an `EmptySet` whose implementation
555556
(state) and behaviour are quite different from non-empty sets -- e.g.
556557
`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`.
560561

561562
In fact the whole thing can become alarmingly deep: *Scala by Example*
562563
also includes a description of `Boolean` as an `abstract class`, and
563564
`True` and `False` as singleton objects which extend `Boolean` and provide
564565
appropriate implementations of the `ifThenElse` method.
565566

566-
And fans of Giuseppe Peano should definitely check out the hypothetical
567-
implementation of `Int`...
568-
569567
### Pass by Name
570568

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(...))
611636

612637
#### Not Just Another Calling Convention
613638

@@ -647,6 +672,8 @@ argument at the call site, nor a reference to the argument at the call
647672
site, but the actual expression that the caller wants it to use to generate
648673
a value.
649674

675+
#### Short-Circuit Evaluation
676+
650677
Same goes for short-circuit evaluation. If you want short-circuit
651678
evaluation in C#, your only hope if to get on the blower to Anders
652679
Hejlsberg and persuade him to bake it into the language:
@@ -685,13 +712,6 @@ for the `condition1`, `condition2`, `ifTrue` and `ifFalse` arguments to be
685712
evaluated by the callee if it needs them, not for the caller to evaluate
686713
them before making the call.
687714

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-
695715
#### Using Pass By Name in Scala
696716

697717
Let's see the custom while implementation again, this time with Scala

0 commit comments

Comments
 (0)
0