First Steps to Scala
来源:互联网 发布:蜘蛛池域名收录 编辑:程序博客网 时间:2024/04/29 22:51
First Steps to Scala
by Bill Venners, Martin Odersky, and Lex Spoon
May 9, 2007
Summary
In this article, you’ll followtwelve steps that are designed to help you understand and gain some basicskills in the Scala programming language.
Scala is a statically typed,object-oriented programming language that blends imperative and functionalprogramming styles. Scala is designed to integrate easily with applicationsthat run on modern virtual machines, primarily the Java virtual machine (JVM).The main Scala compiler, scalac
, generates Java class files thatcan be run on the JVM. However, another Scala compiler exists that generatesbinaries that can be run on the .NET CLR, as Scala is designed to integratewith both the Java and .NET worlds. In the Java world, the Scala language canbe used alongside the Java language—either as an alternative to Java—to buildapplications that run on the JVM.
Scala was developed starting in2003 by Martin Odersky’s group at EPFL, Lausanne, Switzerland.Previously, Martin had been active in the Java field. He co-designed the firstversion of Java generics and was the original author of the current javac
compiler. The work on Scala was motivated by thedesire to overcome limitations imposed by backwards compatibility with Java. SoScala is not a superset of Java, but it retains seamless interoperability.
One reason you might want to useScala is that it allows you to increase your productivity compared to Javawhile leveraging JVM execution speed, your existing investments in Java code,knowledge, and the vast array of APIs available for the JVM. It has theconciseness of a dynamic language like Ruby or Python, but it is staticallytyped, like Java. Another reason is that Scala comes with an Erlang-like Actorslibrary that greatly simplifies concurrent programming, but runs on the JVM.
In Italian, Scala means staircase.In this article, we’ll take you up twelve steps that will help you startbecoming skilled in Scala. The best way to make use of this article is to tryeach example out with the Scala interpeter or compiler. Step 1 explains how todownload and install the Scala distribution.
Step 1. Download and install Scala
To run the examples in thisarticle, you should download Scala from the Scala Downloads page. The examples in this article were run withScala version 2.5.0-RC1, so make sure you download a version at least as recentas 2.5.0-RC1. Once you download an archive file, create a directory whereveryou prefer (perhaps named scala
), and unzip (or untar, etc.) thearchive file in that empty directory. Among the subdirectories created will bethe bin
directory that contains theScala executables, including the compiler and interpeter. To make Scalaconvenient to use, add the full pathname of the bin
directory to your PATH
environment variable. The only other requirementyou’ll need to fulfill is an installation of Java 1.4 or above, which you candownload from http://java.sun.com/. You can also use Scala viaplug-ins for Eclipse and IntelliJ, but for the steps in this article, we’llassume you’re using the Scala distribution from scala-lang.org.
Step 2. Learn to use the Scala interpreter
The easiest way to get started withScala is by using the Scala interpreter, which is an interactive “shell” forwriting Scala expressions and programs. Simply type an expression into the interpreterand it will evaluate the expression and print the resulting value. Theinteractive shell for Scala is simply called scala
. You use it like this:
$ scala
This is an interpreter for Scala.
Type in expressions to have them evaluated.
Type :help for more information.
scala>
After you type an expression, suchas 1 + 2
, and hit return:
scala> 1 + 2
The interpreter will print:
unnamed0: Int = 3
This line includes:
· anautomatically assigned or user-defined name to refer to the computed value (unnamed0
)
· acolon (:
)
· thetype of the expression and its resulting value (Int
)
· anequals sign (=
)
· thevalue resulting from evaluating the expression (3
)
The type Int
names the class Int
in the package scala
.Values of this class are implemented just like Java’s int
values. In fact, Scala treats int
as an alias for scala.Int
. More generally, all of Java’s primitive types aredefined as aliases for classes in the scala
package.For example, if you type boolean
in a Scala program, the typeyou’ll actually get is scala.Boolean
. Or if you type float
, you’ll get scala.Float
. When you compile your Scala code to Java bytecodes, however,Scala will compile these types to Java’s primitive types where possible to getthe performance benefits of Java’s primitive types.
The unnamedX
identifier may be used in later lines. Forinstance, since unnamed0
was set to 3previously, unnamed0 *3
will be 9
:
scala> unnamed0 * 3
unnamed1: Int = 9
To print the necessary, but notsufficient, Hello,world!
greeting, type:
scala> println("Hello, world!")
Hello, world!
unnamed2: Unit = ()
The type of the result hereis scala.Unit
, which is Scala’s analogue to void
in Java. The main difference between Scala’s Unit
and Java’s void
isthat Scala lets you write down a value of type Unit
, namely ()
,whereas in Java there is no value of type void
.(In other words, just as 1
, 2
, and 3
,are potential values of type int
inboth Scala and Java, ()
is the one and only value oftype Unit
in Scala. By contrast, thereare no values of type void
in Java.) Except forthis, Unit
and void
are equivalent. In particular, every void
-returning method in Java is mapped to a Unit
-returning method in Scala.
Step 3. Define some variables
Scala differentiates between val
s, variables that are assigned once and never change,and var
s, variables that may change overtheir lifetime. Here’s a val
definition:
scala> val msg = "Hello, world!"
msg: java.lang.String = Hello, world!
This introduces msg
as a name for the value "Hello world!"
. The type of the value aboveis java.lang.String
, because Scala strings are alsoJava strings. (In fact every Java class is available in Scala.)
This example also points out animportant and very useful feature of Scala: type inference. Notice that younever said the word java.lang.String
or even String
in the val
definition.The Scala interpreter inferred the val
‘stype to be the type of its initialization assignment. Since msg
was initialized to "Hello, world!"
, and since "Hello, world!"
is type java.lang.String
, the compiler gave msg
the type java.lang.String
.
When the Scala interpreter (orcompiler) can infer a type, it is usually best to let it do so rather than fillthe code with unnecessary, explicit type annotations. You can, however, specifya type explicitly if you wish. (For example, you may wish to explicitly specifythe types of public members of classes for documentation purposes.) In contrastto Java, where you specify a variable&8217;s type before its name, in Scalayou specify a variable’s type after its name, separated by a colon. Forexample:
scala> val msg2: java.lang.String = "Hello again, world!"
msg2: java.lang.String = Hello, world!
Or, since java.lang
types are visible with their simple names in Scalaprograms, simply:
scala> val msg3: String = "Hello yet again, world!"
msg3: String = Hello yet again, world!
Going back to our original msg
, now that it is defined, you can then use the msg
value as you’d expect, as in:
scala> println(msg)
Hello, world!
unnamed3: Unit = ()
What you can’t do with msg
, given that it is a val
nota var
, is reassign it. For example, see how the interpretercomplains when you attempt the following:
scala> msg = "Goodbye cruel world!"
<console>:5 error: assignment to non-variable
val unnamed4 = {msg = "Goodbye cruel world!";msg}
If reassignment is what you want,you’ll need to use a var
, as in:
scala> var greeting = "Hello, world!"
greeting: java.lang.String = Hello, world!
Since greeting
is a variable (defined with var
) not a value (defined with val
), you can reassign it later. If you are feeling grouchylater, for example, you could change your greeting
to:
scala> greeting = "Leave me alone, world!"
greeting: java.lang.String = Leave me alone, world!
Step 4. Define some methods
Now that you’ve worked with Scalavariables, you’ll probably want to write some methods. Here’s how you do thatin Scala:
scala> def max(x: Int, y: Int): Int = if (x < y) y else x
max: (Int,Int)Int
Method definitions start with def
instead of val
or var
. The method’s name, in this case max
, is followed by a list of parameters in parentheses. Atype annotation must follow every method parameter, preceded by a colon in theScala way, because the Scala compiler (and interpreter, but from now on we’lljust say compiler) does not infer method parameter types. In this example, themethod named max
takes two parameters, x
and y
,both of type Int
. After the close parenthesisof max
‘s parameter list you’ll find another “: Int
” type specifier. This one defines the result type ofthe max
method itself.
Sometimes the Scala compiler willrequire you to specify the result type of a method. If the method is recursive1, for example, you must explicitly specify the methodresult type. In the case of max
however,you may leave the result type specifier off and the compiler will infer it.Thus, the max
method could have beenwritten:
scala> def max2(x: Int, y: Int) = if (x < y) y else x
max2: (Int,Int)Int
Note that you must alwaysexplicitly specify a method’s parameter types regardless of whether youexplicitly specify its result type.
The name, parameters list, andresult type, if specified, form a method’s signature.After the method’s signature you must put an equals sign and then the body ofthe method. Since max
‘s body consists of just onestatement, you need not place it inside curly braces, but you can if you want.So you could also have written:
scala> def max3(x: Int, y: Int) = { if (x < y) y else x }
max3: (Int,Int)Int
If you want to put more than onestatement in the body of a method, you must enclose them inside curly braces.
Once you have defined a method, youcan call it by name, as in:
scala> max(3, 5)
unnamed6: Int = 5
Note that if a method takes noparameters, as in:
scala> def greet() = println("Hello, world!")
greet: ()Unit
You can call it with or withoutparentheses:
scala> greet()
Hello, world!
unnamed7: Unit = ()
scala> greet
Hello, world!
unnamed8: Unit = ()
The recommended style guideline forsuch method invocations is that if the method may have side effects4, you should provide the parentheses even if thecompiler doesn’t require them. Thus in this case, since the greet
method prints to the standard output, it has sideeffects and you should invoke it with parentheses to alert programmers lookingat the code.
Step 5. Write some Scala scripts
Although Scala is designed to helpdevelopers build large systems, it also scales down nicely such that it feelsnatural to write scripts in it. A script is just a sequence of statements in afile that will be executed sequentially. (By the way, if you’re still runningthe scala interpreter, you can exit it by entering the :quit
command.) Put this into a file named hello.scala
:
println("Hello, world, from a script!")
then run:
>scala hello.scala
And you should get yet anothergreeting:
Hello, world, from a script!
Command line arguments to a Scalascript are available via a Scala array named args
. In Scala, arrays are zero based, as in Java, but youaccess an element by specifying an index in parentheses rather than squarebrackets. So the first element in a Scala array named steps
is steps(0)
, not steps[0]
. To try this out, type thefollowing into a new file named helloarg.scala
:
// Say hello to the first argument
println("Hello, " + args(0) + "!")
then run:
>scala helloarg.scala planet
In this command, "planet"
is passed as a command lineargument, which is accessed in the script as args(0)
. Thus, you should see:
Hello, planet!
Note also that this script includeda comment. As with Java, the Scala compiler will ignore charactersbetween //
and the next end of line, aswell as any characters between /*
and */
. This example also shows strings being concatenatedwith the +
operator. This works as you’dexpect. The expression "Hello," + "world!"
will result in the string "Hello, world!"
.
By the way, if you’re on someflavor of Unix, you can run a Scala script as a shell script by prepending a“pound bang” directive at the top of the file. For example, type the followinginto a file named helloarg
:
#!/bin/sh
exec scala $0 $@
!#
// Say hello to the first argument
println("Hello, " + args(0) + "!")
The initial #!/bin/sh
must be the very first line in the file. Once youset its execute permission:
>chmod +x helloarg
You can run the Scala script as ashell script by simply saying:
>./helloarg globe
Which should yield:
Hello, globe!
Step 6. Loop with while
, decidewith if
You write while
loops in Scala in much the same way you do inJava. Try out a while
by typing the following intoa file name printargs.scala
:
var i = 0
while (i < args.length) {
println(args(i))
i += 1
}
This script starts with a variabledefinition, var i = 0
. Type inference gives i
the type scala.Int
, because that is the type of its initial value, 0
. The while
constructon the next line causes the block (the code between the curly braces) to berepeatedly executed until the boolean expression i < args.length
is false. args.length
gives the length of the args
array, similar to the way you get the length of anarray in Java. The block contains two statements, each indented two spaces, therecommended indentation style for Scala. The first statement, println(args(i))
, prints out the i
th command line argument. The second statement, i += 1
, increments i
byone. Note that Java’s ++i
and i++
don’t work in Scala. To increment in Scala, youneed to say either i = i + 1
or i += 1
. Run this script with the following command:
>scala printargs.scala Scala is fun
And you should see:
Scala
is
fun
For even more fun, type thefollowing code into a new file named echoargs.scala
:
var i = 0
while (i < args.length) {
if (i != 0)
print(" ")
print(args(i))
i += 1
}
println()
In this version, you’ve replacedthe println
call with a print
call, so that all the arguments will be printedout on the same line. To make this readable, you’ve inserted a single spacebefore each argument except the first via the if (i != 0)
construct. Since i != 0
will be false
thefirst time through the while
loop, no space will getprinted before the initial argument. Lastly, you’ve added one more println
to the end, to get a line return after printingout all the arguments. Your output will be very pretty indeed.
If you run this script with thefollowing command:
>scala echoargs.scala Scala is even more fun
You’ll get:
Scala is even more fun
Note that in Scala, as in Java, youmust put the boolean expression for a while
oran if
in parentheses. (In other words, you can’t say inScala things like if i <10
as you can in a language suchas Ruby. You must say if (i <10)
in Scala.) Another similarityto Java is that if a block has only one statement, you can optionally leave offthe curly braces, as demonstrated by the if
statementin echoargs.scala
. And although you haven’t seen many of them, Scala doesuse semi-colons to separate statements as in Java, except that in Scala thesemi-colons are very often optional, giving some welcome relief to your rightpinky finger. If you had been in a more verbose mood, therefore, you could havewritten theechoargs.scala
script as follows:
var i = 0;
while (i < args.length) {
if (i != 0) {
print(" ");
}
print(args(i));
i += 1;
}
println();
If you type the previous code intoa new file named echoargsverbosely.scala
, and run it with the command:
> scala echoargsverbosely.scala In Scala semicolons are often optional
You should see the output:
In Scala semicolons are often optional
Note that because you had noparameters to pass to the println
method, you could have leftoff the parentheses and the compiler would have been perfectly happy. But giventhe style guideline that you should always use parentheses when calling methodsthat may have side effects—coupled with the fact that by printing to thestandard output, println
will indeed have sideeffects—you specified the parentheses even in the concise echoargs.scala
version.
One of the benefits of Scala thatyou can begin to see with these examples, is that Scala gives you theconciseness of a scripting language such as Ruby or Python, but withoutrequiring you to give up the static type checking of more verbose languageslike Java or C++. Scala’s conciseness comes not only from its ability to inferboth types and semicolons, but also its support for the functional programmingstyle, which is discussed in the next step.
Step 7. Iterate with foreach
and for
Although you may not have realizedit, when you wrote the while loops in the previous step, you were programmingin an imperative style. In the imperative style, which isthe style you would ordinarily use with languages like Java, C++, and C, yougive one imperative command at a time, iterate with loops, and often mutatestate shared between different functions or methods. Scala enables you to programimperatively, but as you get to know Scala better, you’ll likely often findyourself programming in a more functional style. In fact, oneof the main aims of the Scalazine will be to help you become as competent atfunctional programming as you are at imperative programming, using Scala as avehicle.
One of the main characteristics ofa functional language is that functions are first class constructs, and that’svery true in Scala. For example, another (far more concise) way to print eachcommand line argument is:
args.foreach(arg => println(arg))
In this code, you call the foreach
method on args
,and pass in a function. In this case, you’re passing in an anonymousfunction (one with no name), which takes one parameternamed arg
. The code of the anonymousfunction isprintln(arg)
. If you type the above code into anew file named pa.scala
, and execute with the command:
scala pa.scala Concise is nice
You should see:
Concise
is
nice
In the previous example, the Scalainterpreter infers type of arg
to be String
, since String
sare what the array on which you’re calling foreach
is holding. If you’d prefer to be more explicit, you canmention the type name, but when you do you’ll need to wrap the argument portionin parentheses (which is the normal form of the syntax anyway). Try typing thisinto a file named epa.scala
.
args.foreach((arg: String) => println(arg))
Running this script has the samebehavior as the previous one. With the command:
scala epa.scala Explicit can be nice too
You’ll get:
Explicit
can
be
nice
too
If instead of an explicit mood,you’re in the mood for even more conciseness, you can take advantage of aspecial case in Scala. If an anonymous function consists of one methodapplication that takes a single argument, you need not explicitly name andspecify the argument. Thus, the following code also works:
args.foreach(println)
To summarize, the syntax for ananonymous function is a list of named parameters, in parentheses, a rightarrow, and then the body of the function. This syntax is illustrated in Figure1.
Figure 1. The syntax of a Scala anonymous function.
Now, by this point you may bewondering what happened to those trusty for loops you have been accustomed tousing in imperative languages such as Java. In an effort to guide you in afunctional direction, only a functional relative of the imperative for
(called a for comprehension) is available inScala. While you won’t see their full power and expressiveness in this article,we will give you a glimpse. In a new file named forprintargs.scala
, type the following:
for (arg <- args)
println(arg)
The parentheses after the for
in this for comprehension contain arg <- args
. To the left of the <-
symbol,which you can say as “in”, is a declaration of a new \@val@ (not a \@var@)named arg
. To the right of <-
is the familiar args
array. When this code executes, arg
will be assigned to each element of the args
array and the body of the for, println(arg)
, will be executed. Scala’s for comprehensions can domuch more than this, but this simple form is similar in functionality to Java5′s:
// ...
for (String arg : args) { // Remember, this is Java, not Scala
System.out.println(arg);
}
// ...
or Ruby’s
for arg in ARGV # Remember, this is Ruby, not Scala
puts arg
end
When you run the forprintargs.scala
script with the command:
scala forprintargs.scala for is functional
You should see:
for
is
functional
Step 8. Parameterize Array
s with types
In addition to being functional,Scala is object-oriented. In Scala, as in Java, you define a blueprint forobjects with classes. From a class blueprint, you can instantiate objects, orclass instances, by using new
. For example, the following Scalacode instantiates a new String
and prints it out:
val s = new String("Hello, world!")
println(s)
In the previous example, you parameterize the String
instance with the initial value "Hello, world!"
. You can think of parameterizationas meaning configuring an instance at the point in your program that you createthat instance. You configure an instance with values by passing objects to aconstructor of the instance in parentheses, just like you do when you create aninstance in Java. If you place the previous code in a new file named paramwithvalues.scala
and run it with scala paramswithvalues.scala
, you’ll see the familiar Hello, world!
greeting printed out.
In addition to parameterizinginstances with values at the point of instantiation, you can in Scala alsoparameterize them with types. This kind of parameterization is akin tospecifying a type in angle brackets when instantiating a generic type in Java 5and beyond. The main difference is that instead of the angle brackets used forthis purpose in Java, in Scala you use square brackets. Here’s an example:
val greetStrings = new Array[String](3)
greetStrings(0) = "Hello"
greetStrings(1) = ", "
greetStrings(2) = "world!\n"
for (i <- 0 to 2)
print(greetStrings(i))
In this example, greetStrings
is a value of type Array[String]
(say this as, “an array of string”) that isinitialized to length 3 by passing the value 3
to a constructor in parentheses in the first lineof code. Type this code into a new file called paramwithtypes.scala
and execute it with scala paramwithtypes.scala
, and you’ll see yet another Hello, world!
greeting. Note that when you parameterize aninstance with both a type and a value, the type comes first in its squarebrackets, followed by the value in parentheses.
Had you been in a more explicitmood, you could have specified the type of greetStrings
explicitly like this:
val greetStrings: Array[String] = new Array[String](3)
// ...
Given Scala’s type inference, thisline of code is semantically equivalent to the actual first line of codein paramwithtypes.scala
. But this form demonstrates thatwhile the type parameterization portion (the type names in square brackets)form part of the type of the instance, the value parameterization part (thevalues in parentheses) do not. The type of greetStrings
is Array[String]
, not Array[String](3)
.
The next three lines of codein paramwithtypes.scala
initializes each element ofthe greetStrings
array:
// ...
greetStrings(0) = "Hello"
greetStrings(1) = ", "
greetStrings(2) = "world!\n"
// ...
As mentioned previously, arrays inScala are accessed by placing the index inside parentheses, not square bracketsas in Java. Thus the zeroeth element of the array is greetStrings(0)
, not greetStrings[0]
as in Java.
These three lines of codeillustrate an important concept to understand about Scala concerning themeaning of val
. When you define a variablewith val
, the variable can’t be reassigned,but the object to which it refers could potentially still be mutated. So inthis case, you couldn’t reassign greetStrings
to a different array; greetStrings
will always point to the same Array[String]
instance with which it was initialized. Butyou can change the elements of thatArray[String]
over time, so the array itself is mutable.
The final two lines in paramwithtypes.scala
contain a for comprehensionthat prints out each greetStrings
array element in turn.
// ...
for (i <- 0 to 2)
print(greetStrings(i))
The first line of code in this forcomprehension illustrates another general rule of Scala: if a method takes onlyone parameter, you can call it without a dot or parentheses. to
is actually a method that takes one Int
argument. The code 0 to 2
is transformed into the method call 0.to(2)
. (This to
methodactually returns not an Array
but a Scala iterator thatreturns the values 0, 1, and 2.) Scala doesn’t technically have operatoroverloading, because it doesn’t actually have operators in the traditionalsense. Characters such as +
, -
, *
, and /
, have no special meaning in Scala, but they can be usedin method names. Thus, the expression 1 + 2
,which was the first Scala code you typed into the interpreter in Step 1, isessential in meaning to 1.+(2)
, where +
is the name of a method defined in class scala.Int
.
Another important idea illustratedby this example will give you insight into why arrays are accessed withparentheses in Scala. Scala has fewer special cases than Java. Arrays aresimply instances of classes like any other class in Scala. When you applyparentheses to a variable and pass in some arguments, Scala will transform thatinto an invocation of a method named apply
.So greetStrings(i)
gets transformed into greetStrings.apply(i)
. Thus accessing the element of anarray in Scala is simply a method call like any other method call. What’s more,the compiler will transform any application of parentheseswith some arguments on any type into an apply method call, not just arrays. Ofcourse it will compile only if that type actually defines an apply
method. So it’s not a special case; it’s a generalrule.
Similarly, when an assignment ismade to a variable that is followed by some arguments in parentheses, thecompiler will transform that into an invocation of an update
method that takes two parameters. For example,
greetStrings(0) = "Hello"
will essentially be transformedinto
greetStrings.update(0, "Hello")
Thus, the following Scala code issemantically equivalent to the code you typed into paramwithtypes.scala
:
val greetStrings = new Array[String](3)
greetStrings.update(0, "Hello")
greetStrings.update(1, ", ")
greetStrings.update(2, "world!\n")
for (i <- 0.to(2))
print(greetStrings.apply(i))
Scala achieves a conceptualsimplicity by treating everything, from arrays to expressions, as objects withmethods. You as the programmer don’t have to remember lots of special cases,such as the differences in Java between primitive and their correspondingwrapper types, or between arrays and regular objects. However, it issignificant to note that in Scala this uniformity does not usually come with aperformance cost as it often has in other languages that have aimed to be purein their object orientation. The Scala compiler uses Java arrays, primitivetypes, and native arithmetic where possible in the compiled code. Thus Scalareally does give you the best of both worlds in this sense: the conceptualsimplicity of a pure object-oriented language with the runtime performancecharacteristics of language that has special cases for performance reasons.
Step 9. Use List
s and Tuple
s
One of the big ideas of thefunctional style of programming is that methods should not have side effects.The only effect of a method should be to compute the value or values that arereturned by the method. Some benefits gained when you take this approach arethat methods become less entangled, and therefore more reliable and reusable.Another benefit of the functional style in a statically typed language is thateverything that goes into and out of a method is checked by a type checker, sologic errors are more likely to manifest themselves as type errors. To applythis functional philosophy to the world of objects, you would make objectsimmutable. A simple example of an immutable object in Java is String
. If you create a String
withthe value "Hello,"
, it will keep that value for therest of its lifetime. If you later call concat("world!")
on that String
,it will not add "world!"
to itself. Instead, it willcreate and return a brand new String
withthe value Hello,world!"
.
As you’ve seen, a Scala Array
is a mutable sequence of objects that all sharethe same type. An Array[String]
contains only String
s, for example. Although you can’t change the length ofan Array
after it is instantiated, you can change itselement values. Thus, Array
s are mutable objects. Animmutable, and therefore more functional-oriented, sequence of objects thatshare the same type is Scala’s List
.As with Array
s, a List[String]
contains only String
s.Scala’sList
, scala.List
, differs from Java’s java.util.List
type in that Scala List
s are always immutable (whereas Java List
s can be mutable). But more importantly, Scala’s List
is designed to enable a functional style ofprogramming. Creating a List
is easy, you just say:
val oneTwoThree = List(1, 2, 3)
This establishes a new \@val@named oneTwoThree
, which initialized with anew List[Int]
with the integer elementvalues 1, 2 and 3. (You don’t need to say new List
because “List
” is defined as a factory method onthe scala.List
singleton object. More on Scala’s singleton objectconstruct in Step 11.) Because List
sare immutable, they behave a bit like Java String
sin that when you call a method on one that might seem by its name to implythe List
will be mutated, it insteadcreates a new List
with the new value andreturns it. For example, List
has a method named :::
that concatenates a passed List
and the List
onwhich :::
was invoked. Here’s how youuse it:
val oneTwo = List(1, 2)
val threeFour = List(3, 4)
val oneTwoThreeFour = oneTwo ::: threeFour
println(oneTwo + " and " + threeFour + " were not mutated.")
println("Thus, " + oneTwoThreeFour + " is a new List.")
Type this code into a new filecalled listcat.scala
and execute it with scala listcat.scala
, and you should see:
List(1, 2) and List(3, 4) were not mutated.
Thus, List(1, 2, 3, 4) is a new List.
Enough said.2
Perhaps the most common operatoryou’ll use with List
s is ::
, which is pronounced “cons.” Cons prepends a newelement to the beginning of an existing List
,and returns the resulting List
. For example, if you type thefollowing code into a file named consit.scala
:
val twoThree = List(2, 3)
val oneTwoThree = 1 :: twoThree
println(oneTwoThree)
And execute it with scala consit.scala
, you should see:
List(1, 2, 3)
Given that a shorthand way tospecify an empty List
is Nil
, one way to initialize new List
s is to string together elements with the cons operator,with Nil
as the last element. Forexample, if you type the following code into a file namedconsinit.scala
:
val oneTwoThree = 1 :: 2 :: 3 :: Nil
println(oneTwoThree)
And execute it with scala consinit.scala
, you should again see:
List(1, 2, 3)
Scala’s List
is packed with useful methods, many of which areshown in Table 1.
What it Is
What it Does
List()
Creates an empty List
Nil
Creates an empty List
List("Cool", "tools", "rule")
Creates a new List[String]
with the three values "Cool"
, "tools"
, and "rule"
val thrill = "Will" :: "fill" :: "until" :: Nil
Creates a new List[String]
with the three values "Will"
, "fill"
, and "until"
thrill(2)
Returns the 2nd element (zero based) of the thrill
List
(returns "until"
)
thrill.count(s => s.length == 4)
Counts the number of String
elements in thrill
that have length 4 (returns 2)
thrill.drop(2)
Returns the thrill
List
without its first 2 elements (returns List("until")
)
thrill.dropRight(2)
Returns the thrill
List
without its rightmost 2 elements (returns List("Will")
)
thrill.exists(s => s == "until")
Determines whether a String
element exists in thrill
that has the value "until"
(returns true
)
thrill.filter(s => s.length == 4)
Returns a List
of all elements, in order, of the thrill
List
that have length 4 (returns List("Will", "fill")
)
thrill.forall(s => s.endsWith("l"))
Indicates whether all elements in the thrill
List
end with the letter "l"
(returns true
)
thrill.foreach(s => print(s))
Executes the print
statement on each of the String
s in the thrill
List
(prints "Willfilluntil"
)
thrill.foreach(print)
Same as the previous, but more concise (also prints "Willfilluntil"
)
thrill.head
Returns the first element in the thrill
List
(returns "Will"
)
thrill.init
Returns a List
of all but the last element in the thrill
List
(returns List("Will", "fill")
)
thrill.isEmpty
Indicates whether the thrill
List
is empty (returns false
)
thrill.last
Returns the last element in the thrill
List
(returns "until"
)
thrill.length
Returns the number of elements in the thrill
List
(returns 3)
thrill.map(s => s + "y")
Returns a List
resulting from adding a "y"
to each String
element in the thrill
List
(returns List("Willy", "filly", "untily")
)
thrill.remove(s => s.length == 4)
Returns a List
of all elements, in order, of the thrill
List
except those that have length 4 (returns List("until")
)
thrill.reverse
Returns a List
containing all element of the thrill
List
in reverse order (returns List("until", "fill", "Will")
)
thrill.sort((s, t) => s.charAt(0).toLowerCase < t.charAt(0).toLowerCase)
Returns a List
containing all element of the thrill
List
in alphabetical order of the first character lowercased (returns List("fill", "until", "Will")
)
thrill.tail
Returns the thrill
List
minus its first element (returns List("fill", "until")
)
Table 1. Some List
methods and usages.
Besides List
, one otherordered collection of object elements that’s very useful in Scala is the tuple. Like List
s, tuples areimmutable, but unlike List
s, tuples can contain different types of elements. Thuswhereas a list might be aList[Int]
or a List[String]
, a tuple could contain both an Int
and a String
at the sametime. Tuples are very useful, for example, if you need to return multipleobjects from a method. Whereas in Java, you would often create a JavaBean-likeclass to hold the multiple return values, in Scala you can simply return atuple. And it is simple: to instantiate a new tuple that holds some objects,just place the objects in parentheses, separated by commas. Once you have atuple instantiated, you can access its elements individually with a dot,underscore, and the one-based index of the element. For example, type thefollowing code into a file named luftballons.scala
:
val pair = (99, "Luftballons")
println(pair._1)
println(pair._2)
In the first line of this code, youcreate a new tuple that contains an Int
withthe value 99 as its first element, and a String
withthe value "Luftballons"
as its second element. Scalainfers the type of the tuple to be Tuple2[Int, String]
, and gives that type to the variable pair
as well. In the second line, you access the _1
field, which will produce the first element, 99.The .
in the second line is thesame dot you’d use to access a field or invoke a method. In this case you areaccessing a field named _1
. If you run this script with scala luftballons.scala
, you’ll see:
99
Luftballons
The actual type of a tuple dependsupon the number and of elements it contains and the types of those elements.Thus, the type of (99,"Luftballons")
is Tuple2[Int, String]
. The type of ('u', 'r', "the", 1, 4,"me")
isTuple6[Char, Char, String, Int, Int, String]
.
Step 10. Use Set
s and Map
s
Because Scala aims to help you takeadvantage of both functional and imperative styles, its collections librariesmake a point to differentiate between mutable and immutable collection classes.For example, Array
s are always mutable, whereas List
s are always immutable. When it comes to Set
s and Map
s,Scala also provides mutable and immutable alternatives, but in a different way.For Set
s and Map
s, Scala models mutability in the class hierarchy.
For example, the Scala API containsa base trait for Set
s,where a trait is similar to a Java interface
. (You’ll find out more about trait
sin Step 12.) Scala then provides two subtraits, one for mutable Set
s, and another for immutableSet
s. As you can see in Figure 2, these three traits allshare the same simple name, Set
.Their fully qualified names differ, however, because they each reside in a differentpackage. Concrete Set
classes in the Scala API,such as theHashSet
classes shown in Figure 2,extend either the mutable or immutable Set
trait.(Although in Java you implement interface
s, in Scala you “extend” traits.) Thus, if you want to use a HashSet
, you can choose between mutable and immutable varietiesdepending upon your needs.
Figure 2. Class hierarchy for Scala Set
s.
To try out Scala Set
s, type the following code into a file named jetset.scala
:
import scala.collection.mutable.HashSet
val jetSet = new HashSet[String]
jetSet += "Lear"
jetSet += ("Boeing", "Airbus")
println(jetSet.contains("Cessna"))
The first line of jetSet.scala
imports the mutable HashSet
. As with Java, the import allows you to use the simplename of the class, HashSet
, in this source file. After ablank line, the third line initializes jetSet
witha new HashSet
that will contain only String
s. Note that just as with List
s and Array
s,when you create a Set
, you need to parameterize it witha type (in this case, String
), since every object in a Set
must share the same type. The subsequent two linesadd three objects to the mutable Set
viathe +=
method. As with most othersymbols you’ve seen that look like operators in Scala, +=
is actually a method defined on class HashSet
. Had you wanted to, instead of writing jetSet += "Lear"
, you could have written jetSet.+=("Lear")
. Because the +=
method takes a variable number of arguments, youcan pass one or more objects at a time to it. For example, jetSet += "Lear"
adds one String
to the HashSet
, but jetSet +=("Boeing", "Airbus")
adds two Strings
to the set. Finally, the last line prints out whether or notthe Set
contains a particular String
. (As you’d expect, it prints false
.)
Another useful collection class inScala is Map
s. As with Set
s, Scala provides mutable and immutable versionsof Map
, using a class hierarchy. As you can see in Figure 3,the class hierarchy for Map
s looks a lot like the onefor Set
s. There’s a base Map
trait in package scala.collection
, and two subtrait Map
s: a mutable Map
in scala.collection.mutable
and an immutable one in scala.collection.immutable
.
Figure 3. Class hierarchy for Scala Map
s.
Implementations of Map
, such as the HashMap
s shown in the class hierarchy in Figure 3, implement either themutable or immutable trait. To see a Map
inaction, type the following code into a file named treasure.scala
.
// In treasure.scala
import scala.collection.mutable.HashMap
val treasureMap = new HashMap[Int, String]
treasureMap += 1 -> "Go to island."
treasureMap += 2 -> "Find big X on ground."
treasureMap += 3 -> "Dig."
println(treasureMap(2))
On the first line of treasure.scala
, you import the mutable form of HashMap
. After a blank line, you define a val
named treasureMap
and initialize it with a new mutable HashMap
whose keys will be Int
s and values String
s.On the next three lines you add key/value pairs to the HashMap
using the ->
method.As illustrated in previous examples, the Scala compiler transforms an binaryoperation expression like 1 ->"Go to island."
into 1.->("Go to island.")
. Thus, when you say 1 -> "Go to island."
, you are actually calling a methodnamed ->
on an Int
with the value 1, and passing in a String
with the value "Go to island."
This ->
method,which you can invoke on any object in a Scala program3, returns a two-element tuple containing the key andvalue. You then pass this tuple to the +=
methodof the HashMap
object to which treasureMap
refers. Finally, the last line prints the valuethat corresponds to the key 2
inthetreasureMap
. If you run this code, it will print:
Find big X on ground.
Because maps are such a usefulprogramming construct, Scala provides a factory method for Map
s that is similar in spirit to the factory method shownin Step 9 that allows you to create List
swithout using the new
keyword. To try out this moreconcise way of constructing maps, type the following code into a filecalled numerals.scala
:
// In numerals.scala
val romanNumeral = Map(1 -> "I", 2 -> "II", 3 -> "III", 4 -> "IV", 5 -> "V")
println(romanNumeral(4))
In numerals.scala
you take advantage of the fact that the theimmutable Map
trait is automaticallyimported into any Scala source file. Thus when you say Map
in the first line of code, the Scala interpreterknows you meanscala.collection.immutable.Map
. In this line, you call a factorymethod on the immutable Map
‘s companion object5, passing in five key/value tuples as parameters. Thisfactory method returns an instance of the immutable HashMap
containing the passed key/value pairs. The name of thefactory method is actually apply
, but as mentioned in Step 8, ifyou say Map(...)
it will be transformed by thecompiler to Map.apply(...)
. If you run the numerals.scala
script, it will print IV
.
Step 11. Understand classes and singleton objects
Up to this point you’ve writtenScala scripts to try out the concepts presented in this article. For all butthe simplest projects, however, you will likely want to partition yourapplication code into classes. To give this a try, type the following code intoa file called greetSimply.scala
:
// In greetSimply.scala
class SimpleGreeter {
val greeting = "Hello, world!"
def greet() = println(greeting)
}
val g = new SimpleGreeter
g.greet()
greetSimply.scala
is actually a Scala script,but one that contains a class definition. This first, example, however,illustrates that as in Java, classes in Scala encapsulate fields and methods.Fields are defined with either val
or var
. Methods are defined with def
. For example, in class SimpleGreeter
, greeting
is a field and greet
is a method. To use the class, you initializea val
named g
witha new instance of SimpleGreeter
. You then invoke the greet
instance method on g
. If you run this script with scala greetSimply.scala
, you will be dazzled with yetanother Hello, world!
.
Although classes in Scala are inmany ways similar to Java, in several ways they are quite different. Onedifference between Java and Scala involves constructors. In Java, classes haveconstructors, which can take parameters, whereas in Scala, classes can takeparameters directly. The Scala notation is more concise—class parameters can beused directly in the body of the class; there’s no need to define fields andwrite assignments that copy constructor parameters into fields. This can yieldsubstantial savings in boilerplate code; especially for small classes. To seethis in action, type the following code into a file named greetFancily.scala
:
// In greetFancily.scala
class FancyGreeter(greeting: String) {
def greet() = println(greeting)
}
val g = new FancyGreeter("Salutations, world")
g.greet
Instead of defining a constructorthat takes a String
, as you would do in Java, in greetFancily.scala
you placed the greeting
parameter of that constructor in parenthesesplaced directly after the name of the class itself, before the open curly braceof the body of class FancyGreeter
. When defined in this way, greeting
essentially becomes a value (not a variable—itcan’t be reassigned) field that’s available anywhere inside the body. In fact,you pass it to println
in the body of the greet
method. If you run this script with thecommand scala greetFancily.scala
, it will inspire you with:
Salutations, world!
This is cool and concise, but whatif you wanted to check the String
passed to FancyGreeter
‘s primary constructor for null
, and throw NullPointerException
to abort the construction of the new instance?Fortunately, you can. Any code sitting inside the curly braces surrounding theclass definition, but which isn’t part of a method definition, is compiled intothe body of the primary constructor. In essence, the primary constructor willfirst initialize what is essentially a final field for each parameter inparentheses following the class name. It will then execute any top-level codecontained in the class’s body. For example, to check a passed parameter for null
, type in the following code into a file namedgreetCarefully.scala
:
// In greetCarefully.scala
class CarefulGreeter(greeting: String) {
if (greeting == null) {
throw new NullPointerException("greeting was null")
}
def greet() = println(greeting)
}
new CarefulGreeter(null)
In greetCarefully.scala
, an if
statement is sitting smack in the middle of theclass body, something that wouldn’t compile in Java. The Scala compiler placesthis if
statement into the body ofthe primary constructor, just after code that initializes what is essentially afinal field named greeting
with the passed value. Thus,if you pass in null
to the primary constructor,as you do in the last line of the greetCarefully.scala
script, the primary constructor will firstinitialize the greeting
field to null
. Then, it will execute the if
statement that checks whether the greeting
field is equal to null
, and since it is, it will throw a NullPointerException
. If you run greetCarefully.scala
, you will see aNullPointerException
stack trace.
In Java, you sometimes give classesmultiple constructors with overloaded parameter lists. You can do that in Scalaas well, however you must pick one of them to be the primary constructor, andplace those constructor parameters directly after the class name. You thenplace any additional auxiliary constructors in thebody of the class as methods named this
.To try this out, type the following code into a file named greetRepeatedly.scala
:
// In greetRepeatedly.scala
class RepeatGreeter(greeting: String, count: Int) {
def this(greeting: String) = this(greeting, 1)
def greet() = {
for (i <- 1 to count)
println(greeting)
}
}
val g1 = new RepeatGreeter("Hello, world", 3)
g1.greet()
val g2 = new RepeatGreeter("Hi there!")
g2.greet()
RepeatGreeter
‘s primary constructor takes not only a String
greeting
parameter, but also an Int
count of the number of times to print thegreeting. However, RepeatGreeter
also contains a definition ofan auxiliary constructor, thethis
method that takes asingle String
greeting
parameter. The body of this constructor consistsof a single statement: an invocation of the primary constructor parameterizedwith the passed greeting
and a count of 1. In thefinal four lines of the greetRepeatedly.scala
script, you create two RepeatGreeter
s instances, one using each constructor, and call greet
on each. If you run greetRepeatedly.scala
, it will print:
Hello, world
Hello, world
Hello, world
Hi there!
Another area in which Scala departsfrom Java is that you can’t have any static fields or methods in a Scala class.Instead, Scala allows you to create singleton objects using thekeyword object
. A singleton object cannot, andneed not, be instantiated with new
.It is essentially automatically instantiated the first time it is used, and asthe “singleton” in its name implies, there is ever only one instance. Asingleton object can share the same name with a class, and when it does, thesingleton is called the class’s companion object. The Scalacompiler transforms the fields and methods of a singleton object to staticfields and methods of the resulting binary Java class. To give this a try, typethe following code into a file named WorldlyGreeter.scala
:
// In WorldlyGreeter.scala
// The WorldlyGreeter class
class WorldlyGreeter(greeting: String) {
def greet() = {
val worldlyGreeting = WorldlyGreeter.worldify(greeting)
println(worldlyGreeting)
}
}
// The WorldlyGreeter companion object
object WorldlyGreeter {
def worldify(s: String) = s + ", world!"
}
In this file, you define both aclass, with the class
keyword, and a companionobject, with the object
keyword. Both types arenamed WorldlyGreeter
. One way to think about this ifyou are coming from a Java programming perspective is that any static methodsthat you would have placed in class WorldlyGreeter
in Java, you’d put in singleton object WorldlyGreeter
in Scala. In fact, when the Scala compilergenerates bytecodes for this file, it will create a Java class named WorldlyGreeter
that has an instance method named greet
(defined in the WorldlyGreeter
class in the Scala source) and a static methodnamed worldify
(defined in the WorldlyGreeter
companion object in Scala source). Note also thatin the first line of the greet
method in class WorldlyGreeter
, you invoke the singleton object’s worldify
method using a syntax similar to the way youinvoke static methods in Java: the singleton object name, a dot, and the methodname:
// Invoking a method on a singleton object from class WorldlyGreeter
// ...
val worldlyGreeting = WorldlyGreeter.worldify(greeting)
// ...
To run this code, you’ll need tocreate an application. Type the following code into a file named WorldlyApp.scala
:
// In WorldlyApp.scala
// A singleton object with a main method that allows
// this singleton object to be run as an application
object WorldlyApp {
def main(args: Array[String]) {
val wg = new WorldlyGreeter("Hello")
wg.greet()
}
}
Because there’s no classnamed WorldlyApp
, this singleton object is not acompanion object. It is instead called a stand-alone.object. Thus, a singleton object is either a companion or a stand-alone object.The distinction is important because companion objects get a few specialprivileges, such as access to private members of the like-named class.
One difference between Scala andJava is that whereas Java requires you to put a public class in a file namedafter the class—for example, you’d put class SpeedRacer
in file SpeedRacer.java
—in Scala, you can name .scala
files anything you want, no matter what Scalaclasses or code you put in them. In general in the case of non-scripts,however, it is recommended style to name files after the classes they containas is done in Java, so that programmers can more easily locate classes by lookingat file names. This is the approach we’ve taken with the two files in thisexample, WorldlyGreeter.scala
and WorldlyApp.scala
.
Neither WorldlyGreeter.scala
nor WorldlyApp.scala
are scripts, because they endin a definition. A script, by contrast, must end in a result expression. Thusif you try to run either of these files as a script, for example by typing:
scala WorldlyGreeter.scala # This won't work!
The Scala interpreter will complainthat WorldlyGreeter.scala
does not end in a resultexpression. Instead, you’ll need to actually compile these files with the Scalacompiler, then run the resulting class files. One way to do this is to usescalac
, which is the basic Scala compiler. Simply type:
scalac WorldlyApp.scala WorldlyGreeter.scala
Given that the scalac
compiler starts up a new JVM instance each time itis invoked, and that the JVM often has a perceptible start-up delay, the Scaladistribution also includes a Scala compiler daemon called fsc
(for fast Scala compiler). You use it like this:
fsc WorldlyApp.scala WorldlyGreeter.scala
The first time you run fsc
, it will create a local server daemon attached to aport on your computer. It will then send the list of files to compile to thedaemon via the port, and the daemon will compile the files. The next time yourun fsc
, the daemon will already berunning, so fsc
will simply send the filelist to the daemon, which will immediately compile the files. Using fsc
, you only need to wait for the the JVM to startup the firsttime. If you ever want to stop the fsc
daemon,you can do so with fsc-shutdown
.
Running either of these scalac
or fsc
commandswill produce Java class files that you can then run via the scala
command, the same command you used to invoke theinterpreter in previous examples. However, instead of giving it a filename witha .scala
extension containing Scala code to interpret6 as you did in every previous example, in this caseyou’ll give it the name of a class containing a main
method. Similar to Java, any Scala class witha main
method that takes a single parameter of type Array[String]
and returns Unit
7 can serve as the entry point to an application. Inthis example, WorldlyApp
has a main
method with the proper signature, so you can runthis example by typing:
scala WorldlyApp
At which point you should see:
Hello, world!
You may recall seeing this outputpreviously, but this time it was generated in this interesting manner:
· The scala
program fires up a JVM withthe WorldlyApp
‘s main
methodas the entry point.
· WordlyApp
‘s main
methodcreates a new WordlyGreeter
instance via new
, passing in the string "Hello"
as a parameter.
· Class WorldlyGreeter
‘s primary constructor essentiallyinitializes a final field named greeting
with the passed value, "Hello"
(this initialization code isautomatically generated by the Scala compiler).
· WordlyApp
‘s main
methodinitializes a local \@val@ named wg
with the new WorldlyGreeter
instance.
· WordlyApp
‘s main
methodthen invokes greet
onthe WorldlyGreeter
instance to which wg
refers.
· Class WordlyGreeter
‘s greet
method invokes worldify
on singleton object WorldlyGreeter
, passing along the value of thefinal field greeting
, "Hello"
.
· Companionobject WorldlyGreeter
‘s worldify
method returns a String
consisting of the value of a concatenation ofthe s
parameter,which is "Hello"
, and the literal String
", world!"
.
· Class WorldlyGreeter
‘s greet
method then initializes a\@val@ named worldlyGreeting
withplaces the "Hello, world!"
String
returned from the worldify
method.
· Class WorldlyGreeter
‘s greet
method passes the "Hello,world!"
String
to which worldlyGreeting
refers to println
, which sends the cheerfulgreeting, via the standard output stream, to you.
Step 12. Understand trait
s and mixins
As first mentioned in Step 10,Scala includes a construct called a trait, which is similar in spirit toJava’s interface
. One main difference betweenJava interface
s and Scala’s traits are thatwhereas all methods in Java interface
s are by definition abstract, you can give methods real bodieswith real code in Scala traits. Here’s an example:
trait Friendly {
def greet() = "Hi"
}
In this example, the greet
method returns the String
"Hi"
. If you are coming from Java,this greet
method may look a littlefunny to you, as if greet()
is somehow a field beinginitialized to the String
value "Hi"
. What is actually going on is that lacking anexplicit return
statement, Scala methods willreturn the value of the last expression. In this case, the value of the lastexpression is "Hi"
, so that is returned. A moreverbose way to say the same thing would be:
trait Friendly {
def greet(): String = {
return "Hi"
}
}
Regardless of how your write themethods, however, the key point is that Scala traits can actually containnon-abstract methods. Another difference between Java interface
s and Scala traits is that whereas you implement Javainterfaces, you extend Scala traits. Otherthan this implements
/extends
difference, however, inheritance when you are defining a newtype works in Scala similarly to Java. In both Java and Scala, a class can extendone (and only one) other class. In Java, an interface
can extend zero to many interface
s. Similarly in Scala, a trait can extend zero to many traits. InJava, a class can implement zero to many interface
s. Similarly in Scala, a class can extend zeroto many traits.implements
is not a keyword in Scala.
Here’s an example:
class Dog extends Friendly {
override def greet() = "Woof"
}
In this example, class Dog
extends trait Friendly
. This inheritance relationship implies much the same thingas interface
implementation does in Java. You can assigna Dog
instance to a variable of type Friendly
. For example:
var pet: Friendly = new Dog
println(pet.greet())
When you invoke the greet
method on the Friendly
pet
variable, it will use dynamicbinding, as in Java, to determine which implementation of the method to call.In this case, class Dog
overrides the greet
method, so Dog
‘simplementation of greet
will be invoked. Were you toexecute the above code, you would get Woof
(Dog
‘s implementation of greet
),not Hi
(Friendly
‘s implementation of greet
).Note that one difference with Java is that to override a method in Scala, youmust precede the method’s def
with override
. If you attempt to override a method withoutspecifying override
, your Scala code won’t compile.
Finally, one quite significantdifference between Java’s interface
s and Scala’s traits is that inScala, you can mix in traits at instantiation time. For example, consider thefollowing trait:
trait ExclamatoryGreeter extends Friendly {
override def greet() = super.greet() + "!"
}
Trait ExclamatoryGreeter
extends trait Friendly
and overrides the greet
method. ExclamatoryGreeter
‘s greet
method first invokes thesuperclass’s greet
method, appends anexclamation point to whatever the superclass’sgreet
methodreturns, and returns the resulting String
.With this trait, you can mix in its behavior atinstantiation time using the with
keyword.Here’s an example:
val pup: Friendly = new Dog with ExclamatoryGreeter
println(pup.greet())
Given the initial line of code, theScala compiler will create a synthetic8 type that extends class Dog
and trait ExclamatoryGreeter
and instantiate it. When you invoke a method onthe synthetic type, it will cause the correct implementation to be invoked.When you run this code, the pup
variablewill first be initialized with the new instance of the synthetic type, thenwhen greet
is invoked on pup
, you’ll see "Woof!"
. Note that had pup
notbeen explicitly defined to be of typeFriendly
, the Scala compiler would have inferred the type of pup
to be Dog with ExclamatoryGreeter
.
To give all these concepts a try,type the following code into a file named friendly.scala
:
trait Friendly {
def greet() = "Hi"
}
class Dog extends Friendly {
override def greet() = "Woof"
}
class HungryCat extends Friendly {
override def greet() = "Meow"
}
class HungryDog extends Dog {
override def greet() = "I'd like to eat my own dog food"
}
trait ExclamatoryGreeter extends Friendly {
override def greet() = super.greet() + "!"
}
var pet: Friendly = new Dog
println(pet.greet())
pet = new HungryCat
println(pet.greet())
pet = new HungryDog
println(pet.greet())
pet = new Dog with ExclamatoryGreeter
println(pet.greet())
pet = new HungryCat with ExclamatoryGreeter
println(pet.greet())
pet = new HungryDog with ExclamatoryGreeter
println(pet.greet())
When you run the friendly.scala
script, it will print:
Woof
Meow
I'd like to eat my own dog food
Woof!
Meow!
I'd like to eat my own dog food!
Conclusion
As you may have glimpsed by readingthis article, the promise of Scala is that you can get more productivity whileleveraging existing investments. Scala’s basic conciseness of syntax andsupport for the functional programming style promise increased programmerproductivity compared to the Java langauge, while enabling you to continue totake advantage of all the great things about the Java platform. You cancomplement Java code with Scala code and continue to leverage your existingJava code and APIs, the many APIs available for the Java platform, the runtimeperformance offered by JVMs, and your own knowledge of the Java platform.
With the knowledge you’ve gained inthis article, you should already be able to get started using Scala for smalltasks, especially scripts. In future articles, we will dive into more detail inthese topics, and introduce other topics that weren’t even hinted at here.
Share your opinion
Have a question or opinion aboutScala? Discuss this article in the Articles Forum topic, First Steps to Scala.
End notes
1. A method is recursive if itcalls itself.
2. Actually, the veryattentive reader may have noticed something amiss with the associativity ofthe :::
method, but it is actually asimple rule to remember. If a method is used as an operator, as in a * b
or a ::: b
, the method is invoked on the left hand operand, as in a.*(b)
, unless the method name ends in a colon. If the methodname ends in a colon, then the method is invoked on the right hand operand, asin b.:::(a)
.
3. The Scala mechanism thatallows you to invoke ->
on any object is called implicitconversion, which will be covered in a future article.
4. A method has sideeffects if it changes state outside the method.
5. Companion objects will becovered in Step 11.
6. The actual mechanism thatthe scala
program uses to “interpret” aScala source file is that it compiles the Scala source code to bytecodes inmemory, loads them immediately via a class loader, and executes them.
7. As mentioned in Step2, Unit
in Scala is similar to void
in Java. Whereas in Java, a main
method must return void
, in Scala, it must return Unit
.
8. A synthetic typeis generated automatically by the compiler rather than being written by hand bythe programmer.
Resources
The Scala programming language homepage is at:
http://www.scala-lang.org/
The Scala mailing list:
http://listes.epfl.ch/cgi-bin/doc_en?liste=scala
The Scala wiki:
http://scala.sygneca.com/
A Scala plug-in for Eclipse:
http://www.scala-lang.org/downloads/eclipse/index.html
A Scala plug-in for IntelliJ:
http://plugins.intellij.net/plugin/?id=1347
The lift Web Framework runs insidea Java web container and uses Scala for coding:
http://liftweb.net/
About the authors
Bill Venners is president ofArtima, Inc., which publishes the Artima Developer website at www.artima.com.He is author of the book, Inside the Java Virtual Machine, a programmer-orientedsurvey of the Java platform’s architecture and internals. His popular columnsin JavaWorld magazine covered Java internals, object-oriented design, and Jini.Bill has been active in the Jini Community since its inception. He led the JiniCommunity’s ServiceUI project, whose ServiceUI API became the de facto standardway to associate user interfaces to Jini services. Bill also serves as anelected member of the Jini Community’s initial Technical Oversight Committee(TOC), and in this role helped to define the governance process for thecommunity.
Martin Odersky is the creator ofthe Scala language. As a professor at EPFL in Lausanne, Switzerland he isworking on programming languages, more specifically languages forobject-oriented and functional programming. His research thesis is that the twoparadigms are two sides of the same coin, to be identified as much as possible.To prove this, he has experimented with a number of language designs, fromPizza to GJ to Functional Nets. He has also influenced the development of Javaas a co-designer of Java generics and as the original author of the currentjavac reference compiler. Since 2001 he has concentrated on designing,implementing, and refining the Scala programming language.Lex Spoon divides histime between working at EPFL in Switzerland and at IBM Research in New YorkState. He holds a Ph.D. from Georgia Tech. He is interested in programminglanguage design and implementation, with special focus on packaging, pluggabletypes, and static analysis for optimization, safe software evolution, andverification of domain-specific properties.
云帆教育大数据学院www.cloudyhadoop.com
通过最新实战课程,系统学习hadoop2.x开发技能,在云帆教育,课程源于企业真实需求,最有实战价值,成为正式会员,可无限制在线学习全部教程;培训市场这么乱,云帆大数据值得你选择!!详情请加入QQ群:374152400 ,咨询课程顾问!
关注云帆教育微信公众号yfteach,第一时间获取公开课信息。
- First Steps to Scala
- First Steps to Scala
- First Steps to Scala
- First Steps to Scala
- Kefa and First Steps
- Focus on Small Steps First, Then Shift to the Larger Goal
- Actionscript 3 - First Steps XI
- First Steps: Developing BizTalk Applications
- QML first steps with QML
- A. Kefa and First Steps
- Codeforces Kefa and First Steps
- solution to Steps
- 7 Steps to MSBuild
- Chapter 2 The first steps in Vim
- Beginning Lua Programming - First steps(第一步)
- iPhone Core Data: Your First Steps
- Python en:First Steps--part one
- First steps of using googleVis on shiny
- JAVA学习第十九课(java程序的异常处理 (二))
- 数据结构实验图论一:基于邻接矩阵的广度优先搜索遍历
- 安装系统过程中分区表(MBR)丢失或损坏
- Maximal Rectangle [leetcode] 的三种思路
- 跟我一起学extjs5(31--加入模块和菜单定义[4前台通过ajax来调用数据与展示])
- First Steps to Scala
- MFC复习和学习 第五章 MFC动态创建 MFC文档 MFC消息处理 MFC单文档应用程序 MFC多文档应用程序
- 解决vc dll导出函数名字发生改变问题
- 将字符串倒序
- Apache Kafka-0.8.1.1源码编译
- 懒汉模式和饿汉模式
- 添加调试选项编译出现错误
- Fedora下载地址
- 配置 Gvim 的 .gvimrc 文件