From b87c78a9e5ee9546bcb5ea63cbb3abd6f961b6a9 Mon Sep 17 00:00:00 2001 From: Santiago Basulto Date: Thu, 26 Jan 2012 12:02:12 -0300 Subject: [PATCH 1/5] java tutorial translated --- es/tutorials/scala-for-java-programmers.md | 698 +++++++++++++++++++++ 1 file changed, 698 insertions(+) create mode 100644 es/tutorials/scala-for-java-programmers.md diff --git a/es/tutorials/scala-for-java-programmers.md b/es/tutorials/scala-for-java-programmers.md new file mode 100644 index 0000000000..5e09e7127d --- /dev/null +++ b/es/tutorials/scala-for-java-programmers.md @@ -0,0 +1,698 @@ +--- +layout: overview +title: Tutorial de Scala para programadores Java + +disqus: true +--- + +Por Michel Schinz y Philipp Haller +Traducción y arreglos Santiago Basulto + +## Introducción + +Este documento provee una rápida introducción al lenguae Scala como también a su compilador. Está pensado para personas que ya poseen cierta experiencia en programación y quieren una vista rápida de lo que pueden hacer con Scala. Se asume como un conocimiento básico de programación orientada a objetos, especialmente en Java. + +## Un primer ejemplo + +Como primer ejemplo, usaremos el programa *Hola mundo* estandar. No es muy fascinante, pero de esta manera resulta fácil demostrar el uso de herramientas de Scala sin saber demasiado acerca del lenguaje. Veamos como luce: + + object HolaMundo { + def main(args: Array[String]) { + println("Hola, mundo!") + } + } + +La estructura de este programa debería ser familiar para programadores Java: consiste de un método llamado `main` que toma los argumentos de la linea de comando (un array de objetos String) como parámetro; el cuerpo de este método consiste en una sola llamada al método predefinido `println` con el saludo amistoso como argumento. El método `main` no retorna un valor (se puede entender como un procedimiento). Por lo tanto, no es necesario que se declare un tipo retorno. + +Lo que es menos familiar a los programadores Java es la declaración de `object` que contiene al método `main`. Esa declaración introduce lo que es comunmente conocido como *objeto singleton*, que es una clase con una sola instancia. Por lo tanto, dicha construcción declara tanto una clase llamada `HolaMundo` como una instancia de esa clase también llamada `HolaMundo`. Esta instancia es creada bajo demanda, es decir, la primera vez que es utilizada. + +El lector astuto notará que el método `main` no es declarado como `static`. Esto es así porque los miembros estáticos (métodos o campos) no existen en Scala. En vez de definir miembros estáticos, el programador de Scala declara estos miembros en un objeto singleton. + +### Compilando el ejemplo + +To compile the example, we use `scalac`, the Scala compiler. `scalac` +works like most compilers: it takes a source file as argument, maybe +some options, and produces one or several object files. The object +files it produces are standard Java class files. + +If we save the above program in a file called +`HelloWorld.scala`, we can compile it by issuing the following +command (the greater-than sign `>` represents the shell prompt +and should not be typed): + + > scalac HelloWorld.scala + +This will generate a few class files in the current directory. One of +them will be called `HelloWorld.class`, and contains a class +which can be directly executed using the `scala` command, as the +following section shows. + +### Running the example + +Once compiled, a Scala program can be run using the `scala` command. +Its usage is very similar to the `java` command used to run Java +programs, and accepts the same options. The above example can be +executed using the following command, which produces the expected +output: + + > scala -classpath . HelloWorld + + Hello, world! + +## Interaction with Java + +One of Scala's strengths is that it makes it very easy to interact +with Java code. All classes from the `java.lang` package are +imported by default, while others need to be imported explicitly. + +Let's look at an example that demonstrates this. We want to obtain +and format the current date according to the conventions used in a +specific country, say France. (Other regions such as the +French-speaking part of Switzerland use the same conventions.) + +Java's class libraries define powerful utility classes, such as +`Date` and `DateFormat`. Since Scala interoperates +seemlessly with Java, there is no need to implement equivalent +classes in the Scala class library--we can simply import the classes +of the corresponding Java packages: + + import java.util.{Date, Locale} + import java.text.DateFormat + import java.text.DateFormat._ + + object FrenchDate { + def main(args: Array[String]) { + val now = new Date + val df = getDateInstance(LONG, Locale.FRANCE) + println(df format now) + } + } + +Scala's import statement looks very similar to Java's equivalent, +however, it is more powerful. Multiple classes can be imported from +the same package by enclosing them in curly braces as on the first +line. Another difference is that when importing all the names of a +package or class, one uses the underscore character (`_`) instead +of the asterisk (`*`). That's because the asterisk is a valid +Scala identifier (e.g. method name), as we will see later. + +The import statement on the third line therefore imports all members +of the `DateFormat` class. This makes the static method +`getDateInstance` and the static field `LONG` directly +visible. + +Inside the `main` method we first create an instance of Java's +`Date` class which by default contains the current date. Next, we +define a date format using the static `getDateInstance` method +that we imported previously. Finally, we print the current date +formatted according to the localized `DateFormat` instance. This +last line shows an interesting property of Scala's syntax. Methods +taking one argument can be used with an infix syntax. That is, the +expression + + df format now + +is just another, slightly less verbose way of writing the expression + + df.format(now) + +This might seem like a minor syntactic detail, but it has important +consequences, one of which will be explored in the next section. + +To conclude this section about integration with Java, it should be +noted that it is also possible to inherit from Java classes and +implement Java interfaces directly in Scala. + +## Everything is an Object + +Scala is a pure object-oriented language in the sense that +*everything* is an object, including numbers or functions. It +differs from Java in that respect, since Java distinguishes +primitive types (such as `boolean` and `int`) from reference +types, and does not enable one to manipulate functions as values. + +### Numbers are objects + +Since numbers are objects, they also have methods. And in fact, an +arithmetic expression like the following: + + 1 + 2 * 3 / x + +consists exclusively of method calls, because it is equivalent to the +following expression, as we saw in the previous section: + + (1).+(((2).*(3))./(x)) + +This also means that `+`, `*`, etc. are valid identifiers +in Scala. + +The parentheses around the numbers in the second version are necessary +because Scala's lexer uses a longest match rule for tokens. +Therefore, it would break the following expression: + + 1.+(2) + +into the tokens `1.`, `+`, and `2`. The reason that +this tokenization is chosen is because `1.` is a longer valid +match than `1`. The token `1.` is interpreted as the +literal `1.0`, making it a `Double` rather than an +`Int`. Writing the expression as: + + (1).+(2) + +prevents `1` from being interpreted as a `Double`. + +### Functions are objects + +Perhaps more surprising for the Java programmer, functions are also +objects in Scala. It is therefore possible to pass functions as +arguments, to store them in variables, and to return them from other +functions. This ability to manipulate functions as values is one of +the cornerstone of a very interesting programming paradigm called +*functional programming*. + +As a very simple example of why it can be useful to use functions as +values, let's consider a timer function whose aim is to perform some +action every second. How do we pass it the action to perform? Quite +logically, as a function. This very simple kind of function passing +should be familiar to many programmers: it is often used in +user-interface code, to register call-back functions which get called +when some event occurs. + +In the following program, the timer function is called +`oncePerSecond`, and it gets a call-back function as argument. +The type of this function is written `() => Unit` and is the type +of all functions which take no arguments and return nothing (the type +`Unit` is similar to `void` in C/C++). The main function of +this program simply calls this timer function with a call-back which +prints a sentence on the terminal. In other words, this program +endlessly prints the sentence "time flies like an arrow" every +second. + + object Timer { + def oncePerSecond(callback: () => Unit) { + while (true) { callback(); Thread sleep 1000 } + } + def timeFlies() { + println("time flies like an arrow...") + } + def main(args: Array[String]) { + oncePerSecond(timeFlies) + } + } + +Note that in order to print the string, we used the predefined method +`println` instead of using the one from `System.out`. + +#### Anonymous functions + +While this program is easy to understand, it can be refined a bit. +First of all, notice that the function `timeFlies` is only +defined in order to be passed later to the `oncePerSecond` +function. Having to name that function, which is only used once, might +seem unnecessary, and it would in fact be nice to be able to construct +this function just as it is passed to `oncePerSecond`. This is +possible in Scala using *anonymous functions*, which are exactly +that: functions without a name. The revised version of our timer +program using an anonymous function instead of *timeFlies* looks +like that: + + object TimerAnonymous { + def oncePerSecond(callback: () => Unit) { + while (true) { callback(); Thread sleep 1000 } + } + def main(args: Array[String]) { + oncePerSecond(() => + println("time flies like an arrow...")) + } + } + +The presence of an anonymous function in this example is revealed by +the right arrow `=>` which separates the function's argument +list from its body. In this example, the argument list is empty, as +witnessed by the empty pair of parenthesis on the left of the arrow. +The body of the function is the same as the one of `timeFlies` +above. + +## Classes + +As we have seen above, Scala is an object-oriented language, and as +such it has a concept of class. (For the sake of completeness, + it should be noted that some object-oriented languages do not have + the concept of class, but Scala is not one of them.) +Classes in Scala are declared using a syntax which is close to +Java's syntax. One important difference is that classes in Scala can +have parameters. This is illustrated in the following definition of +complex numbers. + + class Complex(real: Double, imaginary: Double) { + def re() = real + def im() = imaginary + } + +This complex class takes two arguments, which are the real and +imaginary part of the complex. These arguments must be passed when +creating an instance of class `Complex`, as follows: `new + Complex(1.5, 2.3)`. The class contains two methods, called `re` +and `im`, which give access to these two parts. + +It should be noted that the return type of these two methods is not +given explicitly. It will be inferred automatically by the compiler, +which looks at the right-hand side of these methods and deduces that +both return a value of type `Double`. + +The compiler is not always able to infer types like it does here, and +there is unfortunately no simple rule to know exactly when it will be, +and when not. In practice, this is usually not a problem since the +compiler complains when it is not able to infer a type which was not +given explicitly. As a simple rule, beginner Scala programmers should +try to omit type declarations which seem to be easy to deduce from the +context, and see if the compiler agrees. After some time, the +programmer should get a good feeling about when to omit types, and +when to specify them explicitly. + +### Methods without arguments + +A small problem of the methods `re` and `im` is that, in +order to call them, one has to put an empty pair of parenthesis after +their name, as the following example shows: + + object ComplexNumbers { + def main(args: Array[String]) { + val c = new Complex(1.2, 3.4) + println("imaginary part: " + c.im()) + } + } + +It would be nicer to be able to access the real and imaginary parts +like if they were fields, without putting the empty pair of +parenthesis. This is perfectly doable in Scala, simply by defining +them as methods *without arguments*. Such methods differ from +methods with zero arguments in that they don't have parenthesis after +their name, neither in their definition nor in their use. Our +`Complex` class can be rewritten as follows: + + class Complex(real: Double, imaginary: Double) { + def re = real + def im = imaginary + } + + +### Inheritance and overriding + +All classes in Scala inherit from a super-class. When no super-class +is specified, as in the `Complex` example of previous section, +`scala.AnyRef` is implicitly used. + +It is possible to override methods inherited from a super-class in +Scala. It is however mandatory to explicitly specify that a method +overrides another one using the `override` modifier, in order to +avoid accidental overriding. As an example, our `Complex` class +can be augmented with a redefinition of the `toString` method +inherited from `Object`. + + class Complex(real: Double, imaginary: Double) { + def re = real + def im = imaginary + override def toString() = + "" + re + (if (im < 0) "" else "+") + im + "i" + } + + +## Case Classes and Pattern Matching + +A kind of data structure that often appears in programs is the tree. +For example, interpreters and compilers usually represent programs +internally as trees; XML documents are trees; and several kinds of +containers are based on trees, like red-black trees. + +We will now examine how such trees are represented and manipulated in +Scala through a small calculator program. The aim of this program is +to manipulate very simple arithmetic expressions composed of sums, +integer constants and variables. Two examples of such expressions are +`1+2` and `(x+x)+(7+y)`. + +We first have to decide on a representation for such expressions. The +most natural one is the tree, where nodes are operations (here, the +addition) and leaves are values (here constants or variables). + +In Java, such a tree would be represented using an abstract +super-class for the trees, and one concrete sub-class per node or +leaf. In a functional programming language, one would use an algebraic +data-type for the same purpose. Scala provides the concept of +*case classes* which is somewhat in between the two. Here is how +they can be used to define the type of the trees for our example: + + abstract class Tree + case class Sum(l: Tree, r: Tree) extends Tree + case class Var(n: String) extends Tree + case class Const(v: Int) extends Tree + +The fact that classes `Sum`, `Var` and `Const` are +declared as case classes means that they differ from standard classes +in several respects: + +- the `new` keyword is not mandatory to create instances of + these classes (i.e., one can write `Const(5)` instead of + `new Const(5)`), +- getter functions are automatically defined for the constructor + parameters (i.e., it is possible to get the value of the `v` + constructor parameter of some instance `c` of class + `Const` just by writing `c.v`), +- default definitions for methods `equals` and + `hashCode` are provided, which work on the *structure* of + the instances and not on their identity, +- a default definition for method `toString` is provided, and + prints the value in a "source form" (e.g., the tree for expression + `x+1` prints as `Sum(Var(x),Const(1))`), +- instances of these classes can be decomposed through + *pattern matching* as we will see below. + +Now that we have defined the data-type to represent our arithmetic +expressions, we can start defining operations to manipulate them. We +will start with a function to evaluate an expression in some +*environment*. The aim of the environment is to give values to +variables. For example, the expression `x+1` evaluated in an +environment which associates the value `5` to variable `x`, written +`{ x -> 5 }`, gives `6` as result. + +We therefore have to find a way to represent environments. We could of +course use some associative data-structure like a hash table, but we +can also directly use functions! An environment is really nothing more +than a function which associates a value to a (variable) name. The +environment `{ x -> 5 }` given above can simply be written as +follows in Scala: + + { case "x" => 5 } + +This notation defines a function which, when given the string +`"x"` as argument, returns the integer `5`, and fails with an +exception otherwise. + +Before writing the evaluation function, let us give a name to the type +of the environments. We could of course always use the type +`String => Int` for environments, but it simplifies the program +if we introduce a name for this type, and makes future changes easier. +This is accomplished in Scala with the following notation: + + type Environment = String => Int + +From then on, the type `Environment` can be used as an alias of +the type of functions from `String` to `Int`. + +We can now give the definition of the evaluation function. +Conceptually, it is very simple: the value of a sum of two expressions +is simply the sum of the value of these expressions; the value of a +variable is obtained directly from the environment; and the value of a +constant is the constant itself. Expressing this in Scala is not more +difficult: + + def eval(t: Tree, env: Environment): Int = t match { + case Sum(l, r) => eval(l, env) + eval(r, env) + case Var(n) => env(n) + case Const(v) => v + } + +This evaluation function works by performing *pattern matching* +on the tree `t`. Intuitively, the meaning of the above definition +should be clear: + +1. it first checks if the tree `t` is a `Sum`, and if it + is, it binds the left sub-tree to a new variable called `l` and + the right sub-tree to a variable called `r`, and then proceeds + with the evaluation of the expression following the arrow; this + expression can (and does) make use of the variables bound by the + pattern appearing on the left of the arrow, i.e., `l` and + `r`, +2. if the first check does not succeed, that is, if the tree is not + a `Sum`, it goes on and checks if `t` is a `Var`; if + it is, it binds the name contained in the `Var` node to a + variable `n` and proceeds with the right-hand expression, +3. if the second check also fails, that is if `t` is neither a + `Sum` nor a `Var`, it checks if it is a `Const`, and + if it is, it binds the value contained in the `Const` node to a + variable `v` and proceeds with the right-hand side, +4. finally, if all checks fail, an exception is raised to signal + the failure of the pattern matching expression; this could happen + here only if more sub-classes of `Tree` were declared. + +We see that the basic idea of pattern matching is to attempt to match +a value to a series of patterns, and as soon as a pattern matches, +extract and name various parts of the value, to finally evaluate some +code which typically makes use of these named parts. + +A seasoned object-oriented programmer might wonder why we did not +define `eval` as a *method* of class `Tree` and its +subclasses. We could have done it actually, since Scala allows method +definitions in case classes just like in normal classes. Deciding +whether to use pattern matching or methods is therefore a matter of +taste, but it also has important implications on extensibility: + +- when using methods, it is easy to add a new kind of node as this + can be done just by defining a sub-class of `Tree` for it; on + the other hand, adding a new operation to manipulate the tree is + tedious, as it requires modifications to all sub-classes of + `Tree`, +- when using pattern matching, the situation is reversed: adding a + new kind of node requires the modification of all functions which do + pattern matching on the tree, to take the new node into account; on + the other hand, adding a new operation is easy, by just defining it + as an independent function. + +To explore pattern matching further, let us define another operation +on arithmetic expressions: symbolic derivation. The reader might +remember the following rules regarding this operation: + +1. the derivative of a sum is the sum of the derivatives, +2. the derivative of some variable `v` is one if `v` is the + variable relative to which the derivation takes place, and zero + otherwise, +3. the derivative of a constant is zero. + +These rules can be translated almost literally into Scala code, to +obtain the following definition: + + def derive(t: Tree, v: String): Tree = t match { + case Sum(l, r) => Sum(derive(l, v), derive(r, v)) + case Var(n) if (v == n) => Const(1) + case _ => Const(0) + } + +This function introduces two new concepts related to pattern matching. +First of all, the `case` expression for variables has a +*guard*, an expression following the `if` keyword. This +guard prevents pattern matching from succeeding unless its expression +is true. Here it is used to make sure that we return the constant `1` +only if the name of the variable being derived is the same as the +derivation variable `v`. The second new feature of pattern +matching used here is the *wildcard*, written `_`, which is +a pattern matching any value, without giving it a name. + +We did not explore the whole power of pattern matching yet, but we +will stop here in order to keep this document short. We still want to +see how the two functions above perform on a real example. For that +purpose, let's write a simple `main` function which performs +several operations on the expression `(x+x)+(7+y)`: it first computes +its value in the environment `{ x -> 5, y -> 7 }`, then +computes its derivative relative to `x` and then `y`. + + def main(args: Array[String]) { + val exp: Tree = Sum(Sum(Var("x"),Var("x")),Sum(Const(7),Var("y"))) + val env: Environment = { case "x" => 5 case "y" => 7 } + println("Expression: " + exp) + println("Evaluation with x=5, y=7: " + eval(exp, env)) + println("Derivative relative to x:\n " + derive(exp, "x")) + println("Derivative relative to y:\n " + derive(exp, "y")) + } + +Executing this program, we get the expected output: + + Expression: Sum(Sum(Var(x),Var(x)),Sum(Const(7),Var(y))) + Evaluation with x=5, y=7: 24 + Derivative relative to x: + Sum(Sum(Const(1),Const(1)),Sum(Const(0),Const(0))) + Derivative relative to y: + Sum(Sum(Const(0),Const(0)),Sum(Const(0),Const(1))) + +By examining the output, we see that the result of the derivative +should be simplified before being presented to the user. Defining a +basic simplification function using pattern matching is an interesting +(but surprisingly tricky) problem, left as an exercise for the reader. + +## Traits + +Apart from inheriting code from a super-class, a Scala class can also +import code from one or several *traits*. + +Maybe the easiest way for a Java programmer to understand what traits +are is to view them as interfaces which can also contain code. In +Scala, when a class inherits from a trait, it implements that trait's +interface, and inherits all the code contained in the trait. + +To see the usefulness of traits, let's look at a classical example: +ordered objects. It is often useful to be able to compare objects of a +given class among themselves, for example to sort them. In Java, +objects which are comparable implement the `Comparable` +interface. In Scala, we can do a bit better than in Java by defining +our equivalent of `Comparable` as a trait, which we will call +`Ord`. + +When comparing objects, six different predicates can be useful: +smaller, smaller or equal, equal, not equal, greater or equal, and +greater. However, defining all of them is fastidious, especially since +four out of these six can be expressed using the remaining two. That +is, given the equal and smaller predicates (for example), one can +express the other ones. In Scala, all these observations can be +nicely captured by the following trait declaration: + + trait Ord { + def < (that: Any): Boolean + def <=(that: Any): Boolean = (this < that) || (this == that) + def > (that: Any): Boolean = !(this <= that) + def >=(that: Any): Boolean = !(this < that) + } + +This definition both creates a new type called `Ord`, which +plays the same role as Java's `Comparable` interface, and +default implementations of three predicates in terms of a fourth, +abstract one. The predicates for equality and inequality do not appear +here since they are by default present in all objects. + +The type `Any` which is used above is the type which is a +super-type of all other types in Scala. It can be seen as a more +general version of Java's `Object` type, since it is also a +super-type of basic types like `Int`, `Float`, etc. + +To make objects of a class comparable, it is therefore sufficient to +define the predicates which test equality and inferiority, and mix in +the `Ord` class above. As an example, let's define a +`Date` class representing dates in the Gregorian calendar. Such +dates are composed of a day, a month and a year, which we will all +represent as integers. We therefore start the definition of the +`Date` class as follows: + + class Date(y: Int, m: Int, d: Int) extends Ord { + def year = y + def month = m + def day = d + override def toString(): String = year + "-" + month + "-" + day + +The important part here is the `extends Ord` declaration which +follows the class name and parameters. It declares that the +`Date` class inherits from the `Ord` trait. + +Then, we redefine the `equals` method, inherited from +`Object`, so that it correctly compares dates by comparing their +individual fields. The default implementation of `equals` is not +usable, because as in Java it compares objects physically. We arrive +at the following definition: + + override def equals(that: Any): Boolean = + that.isInstanceOf[Date] && { + val o = that.asInstanceOf[Date] + o.day == day && o.month == month && o.year == year + } + +This method makes use of the predefined methods `isInstanceOf` +and `asInstanceOf`. The first one, `isInstanceOf`, +corresponds to Java's `instanceof` operator, and returns true +if and only if the object on which it is applied is an instance of the +given type. The second one, `asInstanceOf`, corresponds to +Java's cast operator: if the object is an instance of the given type, +it is viewed as such, otherwise a `ClassCastException` is +thrown. + +Finally, the last method to define is the predicate which tests for +inferiority, as follows. It makes use of another predefined method, +`error`, which throws an exception with the given error message. + + def <(that: Any): Boolean = { + if (!that.isInstanceOf[Date]) + error("cannot compare " + that + " and a Date") + + val o = that.asInstanceOf[Date] + (year < o.year) || + (year == o.year && (month < o.month || + (month == o.month && day < o.day))) + } + +This completes the definition of the `Date` class. Instances of +this class can be seen either as dates or as comparable objects. +Moreover, they all define the six comparison predicates mentioned +above: `equals` and `<` because they appear directly in +the definition of the `Date` class, and the others because they +are inherited from the `Ord` trait. + +Traits are useful in other situations than the one shown here, of +course, but discussing their applications in length is outside the +scope of this document. + +## Genericity + +The last characteristic of Scala we will explore in this tutorial is +genericity. Java programmers should be well aware of the problems +posed by the lack of genericity in their language, a shortcoming which +is addressed in Java 1.5. + +Genericity is the ability to write code parametrized by types. For +example, a programmer writing a library for linked lists faces the +problem of deciding which type to give to the elements of the list. +Since this list is meant to be used in many different contexts, it is +not possible to decide that the type of the elements has to be, say, +`Int`. This would be completely arbitrary and overly +restrictive. + +Java programmers resort to using `Object`, which is the +super-type of all objects. This solution is however far from being +ideal, since it doesn't work for basic types (`int`, +`long`, `float`, etc.) and it implies that a lot of +dynamic type casts have to be inserted by the programmer. + +Scala makes it possible to define generic classes (and methods) to +solve this problem. Let us examine this with an example of the +simplest container class possible: a reference, which can either be +empty or point to an object of some type. + + class Reference[T] { + private var contents: T = _ + def set(value: T) { contents = value } + def get: T = contents + } + +The class `Reference` is parametrized by a type, called `T`, +which is the type of its element. This type is used in the body of the +class as the type of the `contents` variable, the argument of +the `set` method, and the return type of the `get` method. + +The above code sample introduces variables in Scala, which should not +require further explanations. It is however interesting to see that +the initial value given to that variable is `_`, which represents +a default value. This default value is 0 for numeric types, +`false` for the `Boolean` type, `()` for the `Unit` +type and `null` for all object types. + +To use this `Reference` class, one needs to specify which type to use +for the type parameter `T`, that is the type of the element +contained by the cell. For example, to create and use a cell holding +an integer, one could write the following: + + object IntegerReference { + def main(args: Array[String]) { + val cell = new Reference[Int] + cell.set(13) + println("Reference contains the half of " + (cell.get * 2)) + } + } + +As can be seen in that example, it is not necessary to cast the value +returned by the `get` method before using it as an integer. It +is also not possible to store anything but an integer in that +particular cell, since it was declared as holding an integer. + +## Conclusion + +This document gave a quick overview of the Scala language and +presented some basic examples. The interested reader can go on, for example, by +reading the document *Scala By Example*, which +contains much more advanced examples, and consult the *Scala + Language Specification* when needed. From 28178975c53845ab4ec83a48388763b01580bd3e Mon Sep 17 00:00:00 2001 From: Santiago Basulto Date: Mon, 30 Jan 2012 17:02:26 -0300 Subject: [PATCH 2/5] Translating scala-for-java-programmers --- es/tutorials/scala-for-java-programmers.md | 469 +++++++-------------- 1 file changed, 148 insertions(+), 321 deletions(-) diff --git a/es/tutorials/scala-for-java-programmers.md b/es/tutorials/scala-for-java-programmers.md index 5e09e7127d..06d433a7d8 100644 --- a/es/tutorials/scala-for-java-programmers.md +++ b/es/tutorials/scala-for-java-programmers.md @@ -8,6 +8,11 @@ disqus: true Por Michel Schinz y Philipp Haller Traducción y arreglos Santiago Basulto +Comentarios: + * No es necesario un archivo por clase + * Forma de utilizar funcional con interfaces en Java + * Comparación de funciones anónimas con clases anónimas + ## Introducción Este documento provee una rápida introducción al lenguae Scala como también a su compilador. Está pensado para personas que ya poseen cierta experiencia en programación y quieren una vista rápida de lo que pueden hacer con Scala. Se asume como un conocimiento básico de programación orientada a objetos, especialmente en Java. @@ -30,51 +35,29 @@ El lector astuto notará que el método `main` no es declarado como `static`. Es ### Compilando el ejemplo -To compile the example, we use `scalac`, the Scala compiler. `scalac` -works like most compilers: it takes a source file as argument, maybe -some options, and produces one or several object files. The object -files it produces are standard Java class files. +Para compilar el ejemplo utilizaremos `scalac`, el compilador de Scala. `scalac` funciona como la mayoría de los compiladores. Toma un archivo fuente como argumento, algunas opciones y produce uno o varios archivos objeto. Los archivos objeto que produce son archivos class de Java estandar. -If we save the above program in a file called -`HelloWorld.scala`, we can compile it by issuing the following -command (the greater-than sign `>` represents the shell prompt -and should not be typed): +Si guardamos el programa anterior en un archivo llamado `HolaMundo.scala`, podemos compilarlo ejecutando el siguiente comando (el símbolo mayor `>` representa el prompt del shell y no debe ser tipeado): - > scalac HelloWorld.scala + > scalac HolaMundo.scala -This will generate a few class files in the current directory. One of -them will be called `HelloWorld.class`, and contains a class -which can be directly executed using the `scala` command, as the -following section shows. +Esto generará algunos archivos class en el directorio actual. Uno de ellos se llamará `HolaMundo.class` y contiene una clase que puede ser directamente ejecutada utilizando el comando `scala`, como mostramos en la siguiente sección. -### Running the example +### Ejecutando el ejemplo -Once compiled, a Scala program can be run using the `scala` command. -Its usage is very similar to the `java` command used to run Java -programs, and accepts the same options. The above example can be -executed using the following command, which produces the expected -output: +Una vez compilado, un programa Scala puede ser ejecutado utilizando el comando `scala`. Su uso es muy similar al comando `java` utilizado para ejecutar programas Java, y acepta las mismas opciones. El ejemplo de arriba puede ser ejecutado utilizando el siguiente comando, que produce la salida esperada: - > scala -classpath . HelloWorld + > scala -classpath . HolaMundo - Hello, world! + Hola, mundo! -## Interaction with Java +## Interacción con Java -One of Scala's strengths is that it makes it very easy to interact -with Java code. All classes from the `java.lang` package are -imported by default, while others need to be imported explicitly. +Una de las fortalezas de Scala es que hace muy fácil interactuar con código Java. Todas las clases del paquete `java.lang` son importadas por defecto, mientras otras necesitan ser importadas explicitamente. -Let's look at an example that demonstrates this. We want to obtain -and format the current date according to the conventions used in a -specific country, say France. (Other regions such as the -French-speaking part of Switzerland use the same conventions.) +Veamos un ejemplo que demuestra esto. Queremos obtener y formatear la fecha actual de acuerdo a convenciones utilizadas en un país específico, por ejemplo Francia. -Java's class libraries define powerful utility classes, such as -`Date` and `DateFormat`. Since Scala interoperates -seemlessly with Java, there is no need to implement equivalent -classes in the Scala class library--we can simply import the classes -of the corresponding Java packages: +Las librerías de clases de Java definen clases de utilería poderosas, como `Date` y `DateFormat`. Ya que Scala interacciona fácilmente con Java, no es necesario implementar estas clases equivalentes en las librerías de Scala --podemos simplemente importar las clases de los correspondientes paquetes de Java: import java.util.{Date, Locale} import java.text.DateFormat @@ -82,259 +65,153 @@ of the corresponding Java packages: object FrenchDate { def main(args: Array[String]) { - val now = new Date + val ahora = new Date val df = getDateInstance(LONG, Locale.FRANCE) - println(df format now) + println(df format ahora) } } -Scala's import statement looks very similar to Java's equivalent, -however, it is more powerful. Multiple classes can be imported from -the same package by enclosing them in curly braces as on the first -line. Another difference is that when importing all the names of a -package or class, one uses the underscore character (`_`) instead -of the asterisk (`*`). That's because the asterisk is a valid -Scala identifier (e.g. method name), as we will see later. - -The import statement on the third line therefore imports all members -of the `DateFormat` class. This makes the static method -`getDateInstance` and the static field `LONG` directly -visible. +Las declaraciones de importación de Scala lucen muy similares a las de Java, sin embargo, las primeras son bastante más poderosas. Múltiples clases pueden ser importadas desde el mismo paquete al encerrarlas en llaves como se muestra en la primer linea. Otra diferencia es que podemos importar todos los nombres de un paquete o clase, utilizando el caracter guión bajo (`_`) en vez del asterisco (`*`). Eso es porque el asterisco es un identificador válido en Scala (quiere decir que por ejemplo podemos nombrar a un método `*`), como veremos más adelante. -Inside the `main` method we first create an instance of Java's -`Date` class which by default contains the current date. Next, we -define a date format using the static `getDateInstance` method -that we imported previously. Finally, we print the current date -formatted according to the localized `DateFormat` instance. This -last line shows an interesting property of Scala's syntax. Methods -taking one argument can be used with an infix syntax. That is, the -expression +La declaración `import` en la tercer linea por lo tanto importa todos los miembros de la clase `DateFormat`. Esto hace que el método estático `getDateInstance` y el campo estático `LONG` sean directamente visibles. - df format now +Dentro del método `main` primero creamos una instancia de la clase `Date` la cual por defecto contiene la fecha actual. A continuación definimos un formateador de fechas utilizando el método estático `getDateInstance` que importamos previamente. Finalmente, imprimimos la fecha actual formateada de acuerdo a la instancia de `DateFormat` que fue "localizada". Esta última linea muestra una propiedad interesante de la sintaxis de Scala. Los métodos que toman un solo argumento pueden ser usados con una sintaxis de infijo Es decir, la expresión -is just another, slightly less verbose way of writing the expression + df format ahora + +es solamente otra manera más corta de escribir la expresión: - df.format(now) + df.format(ahora) -This might seem like a minor syntactic detail, but it has important -consequences, one of which will be explored in the next section. +Esto parece tener como un detalle sintáctico menor, pero tiene importantes consecuencias, una de ellas la exploraremos en la próxima sección. -To conclude this section about integration with Java, it should be -noted that it is also possible to inherit from Java classes and -implement Java interfaces directly in Scala. +Para concluir esta sección sobre la interacción con Java, es importante notar que es también posible heredar de clases Java e implementar interfaces Java directamente en Scala. -## Everything is an Object +## Todo es un objeto -Scala is a pure object-oriented language in the sense that -*everything* is an object, including numbers or functions. It -differs from Java in that respect, since Java distinguishes -primitive types (such as `boolean` and `int`) from reference -types, and does not enable one to manipulate functions as values. +Scala es un lenguaje puramente orientado a objetos en el sentido de que *todo* es un objeto, incluyendo números o funciones. Difiere de Java en este aspecto, ya que Java distingue tipos primitivos (como `boolean` e `int`) de tipos referencialbes, y no nos permite manipular las funciones como valores. ### Numbers are objects -Since numbers are objects, they also have methods. And in fact, an -arithmetic expression like the following: +Ya que los números son objetos, estos también tienen métodos. De hecho, una expresión aritmética como la siguiente: 1 + 2 * 3 / x -consists exclusively of method calls, because it is equivalent to the -following expression, as we saw in the previous section: +Consiste exclusivamente de llamadas a métodos, porque es equivalente a la siguiente expresión, como vimos en la sección anterior: (1).+(((2).*(3))./(x)) -This also means that `+`, `*`, etc. are valid identifiers -in Scala. +Esto también indica que `+`, `*`, etc son identificadores válidos en Scala. -The parentheses around the numbers in the second version are necessary -because Scala's lexer uses a longest match rule for tokens. -Therefore, it would break the following expression: +Los paréntesis alrededor de los números en la segunda versión son necesarios porque el analizador léxico de Scala usa la regla de "mayor coincidencia". Por lo tanto partiría la siguiente expresión: 1.+(2) -into the tokens `1.`, `+`, and `2`. The reason that -this tokenization is chosen is because `1.` is a longer valid -match than `1`. The token `1.` is interpreted as the -literal `1.0`, making it a `Double` rather than an -`Int`. Writing the expression as: +En estas partes: `1.`, `+`, y `2`. La razón que esta regla es elegida es porque `1.` es una coincidencia válida y es mayor que `1`, haciendo a este un `Double` en vez de un `Int`. Al escribir la expresión así: (1).+(2) -prevents `1` from being interpreted as a `Double`. - -### Functions are objects - -Perhaps more surprising for the Java programmer, functions are also -objects in Scala. It is therefore possible to pass functions as -arguments, to store them in variables, and to return them from other -functions. This ability to manipulate functions as values is one of -the cornerstone of a very interesting programming paradigm called -*functional programming*. - -As a very simple example of why it can be useful to use functions as -values, let's consider a timer function whose aim is to perform some -action every second. How do we pass it the action to perform? Quite -logically, as a function. This very simple kind of function passing -should be familiar to many programmers: it is often used in -user-interface code, to register call-back functions which get called -when some event occurs. - -In the following program, the timer function is called -`oncePerSecond`, and it gets a call-back function as argument. -The type of this function is written `() => Unit` and is the type -of all functions which take no arguments and return nothing (the type -`Unit` is similar to `void` in C/C++). The main function of -this program simply calls this timer function with a call-back which -prints a sentence on the terminal. In other words, this program -endlessly prints the sentence "time flies like an arrow" every -second. - - object Timer { - def oncePerSecond(callback: () => Unit) { +previene que el `1` sea tomado como un `Double`. + +### Las funciones son objetos + +Tal vez suene más sorprendente para los programadores Java, las funciones en Scala también son objetos. Por lo tanto es posible pasar funciones como argumentos, almacenarlas en variables, y retornarlas desde otras funciones. Esta habilidad de manipular funciones como valores es una de las valores fundamentales de un paradigma de programación muy interesante llamado *programación funcional*. + +Como un ejemplo muy simple de por qué puede ser útil usar funciones como valores consideremos una función *temporizador* (o timer, en inglés) cuyo propósito es realizar alguna acción cada un segundo. ¿Cómo pasamos al temporizador la acción a realizar? Bastante lógico, como una función. Este simple concepto de pasar funciones debería ser familiar para muchos programadores: es generalmente utilizado en código relacionado con Interfaces gráficas de usuario (GUIs) para registrar "retrollamadas" (call-back en inglés) que son invocadas cuando un evento ocurre. + +En el siguiente programa, la función del temporizador se llama `unaVezPorSegundo` y recibe una función call-back como argumento. El tipo de esta función es escrito de la siguiente manera: `() => Unit` y es el tipo de todas las funciones que no toman argumentos ni retornan valores (el tipo `Unit` es similar a `void` en Java/C/C++). La función principal de este programa simplemente invoca esta función temporizador con una call-back que imprime una sentencia en la terminal. En otras palabras, este programa imprime interminablemente la sentencia "El tiemplo vuela como una flecha" cada segundo. + + object Temporizador { + def unaVezPorSegundo(callback: () => Unit) { while (true) { callback(); Thread sleep 1000 } } - def timeFlies() { - println("time flies like an arrow...") + def tiempoVuela() { + println("El tiemplo vuela como una flecha...") } def main(args: Array[String]) { - oncePerSecond(timeFlies) + unaVezPorSegundo(tiempoVuela) } } - + +_Nota: si nunca tuviste experiencias previas con programación funcional te recomiendo que te tomes unos segundos para analizar cuando se utilizan paréntesis y cuando no en los lugares donde aparece *callback*. Por ejemplo, dentro de la declaración de `unaVezPorSegundo` no aparece, ya que se trata de la función como un "valor", a diferencia de cómo aparece dentro del método, ya que en ese caso se la está invocando (por eso los paréntesis)._ Note that in order to print the string, we used the predefined method `println` instead of using the one from `System.out`. -#### Anonymous functions - -While this program is easy to understand, it can be refined a bit. -First of all, notice that the function `timeFlies` is only -defined in order to be passed later to the `oncePerSecond` -function. Having to name that function, which is only used once, might -seem unnecessary, and it would in fact be nice to be able to construct -this function just as it is passed to `oncePerSecond`. This is -possible in Scala using *anonymous functions*, which are exactly -that: functions without a name. The revised version of our timer -program using an anonymous function instead of *timeFlies* looks -like that: - - object TimerAnonymous { - def oncePerSecond(callback: () => Unit) { +#### Funciones anónimas + +El programa anterior es fácil de entender, pero puede ser refinado aún más. Primero que nada es interesante notar que la función `tiempoVuela` está definida solamente para ser pasada posteriormente a la función `unaVezPorSegundo`. Tener que nombrar esa función, que es utilizada solamente una vez parece un poco innecesario y sería bueno poder construirla justo cuando sea pasada a `unaVezPorSegundo`. Esto es posible en Scala utilizando *funciones anónimas*, que son exactamente eso: funciones sin nombre. La versión revisada de nuestro temporizador utilizando una función anónima luce así: + + object TemporizadorAnonimo { + def unaVezPorSegundo(callback: () => Unit) { while (true) { callback(); Thread sleep 1000 } } def main(args: Array[String]) { - oncePerSecond(() => - println("time flies like an arrow...")) + unaVezPorSegundo( + () => println("El tiemplo vuela como una flecha...") + ) } } -The presence of an anonymous function in this example is revealed by -the right arrow `=>` which separates the function's argument -list from its body. In this example, the argument list is empty, as -witnessed by the empty pair of parenthesis on the left of the arrow. -The body of the function is the same as the one of `timeFlies` -above. - -## Classes - -As we have seen above, Scala is an object-oriented language, and as -such it has a concept of class. (For the sake of completeness, - it should be noted that some object-oriented languages do not have - the concept of class, but Scala is not one of them.) -Classes in Scala are declared using a syntax which is close to -Java's syntax. One important difference is that classes in Scala can -have parameters. This is illustrated in the following definition of -complex numbers. - - class Complex(real: Double, imaginary: Double) { +La presencia de una función anónima en este ejemplo es revelada por la flecha a la derecha `=>` que separa los argumentos de la función del cuerpo de esta. En este ejemplo, la lista de argumentos está vacía, como se ve por el par de paréntesis vacíos a la izquierda de la flecha. El cuerpo de la función es el mismo que en `tiempoVuela` del programa anterior. + +## Clases + +Como hemos visto anteriormente, Scala es un lenguaje orientado a objetos, y como tal tiene el concepto de Clase (en realidad existen lenguajes orientados a objetos que no cuentan con el concepto de clases, pero Scala no es uno de ellos). Las clases en Scala son declaradas utilizando una sintaxis que es cercana a la de Java. Una diferencia importante es que las clases en Scala pueden tener parámetros. Ilustramos esto en el siguiente ejemplo, la definición de un número complejo: + + class Complejo(real: Double, imaginaria: Double) { def re() = real - def im() = imaginary + def im() = imaginaria } -This complex class takes two arguments, which are the real and -imaginary part of the complex. These arguments must be passed when -creating an instance of class `Complex`, as follows: `new - Complex(1.5, 2.3)`. The class contains two methods, called `re` -and `im`, which give access to these two parts. - -It should be noted that the return type of these two methods is not -given explicitly. It will be inferred automatically by the compiler, -which looks at the right-hand side of these methods and deduces that -both return a value of type `Double`. - -The compiler is not always able to infer types like it does here, and -there is unfortunately no simple rule to know exactly when it will be, -and when not. In practice, this is usually not a problem since the -compiler complains when it is not able to infer a type which was not -given explicitly. As a simple rule, beginner Scala programmers should -try to omit type declarations which seem to be easy to deduce from the -context, and see if the compiler agrees. After some time, the -programmer should get a good feeling about when to omit types, and -when to specify them explicitly. - -### Methods without arguments - -A small problem of the methods `re` and `im` is that, in -order to call them, one has to put an empty pair of parenthesis after -their name, as the following example shows: - - object ComplexNumbers { +Esta clase compleja toma dos argumentos, que son las partes real e imaginarias de un número complejo. Estos argumentos deben ser pasados cuando se crea una instancia de la clase `Complejo`, de la siguiente manera: + + new Complejo(1.5, 2.3) + +La clase contiene dos métodos llamados `re` e `im`, que proveen acceso a las dos partes del número. + +Debe notarse que el tipo de retorno de estos dos métodos no está expresado explicitamente. Será inferido automáticamente por el compilador, que primero mira la parte derecha de estos métodos y puede deducir que ambos retornan un valor de tipo `Double`. + +El compilador no es siempre capaz de inferir los tipos como lo hace aquí, y desafortunadamente no existe una regla simple para saber cuándo será y cuándo no. En la práctica, esto generalmente no es un problema ya que el compilador se queja cuando no es capaz de inferir un tipo que no fue explicitamente fijado. Como regla simple, los programadores de Scala novatos deberían tratar de omitir las declaraciones de tipos que parecen ser simples de deducir del contexto y ver si el compilador no lanza errores. Después de algún tiempo, el programador debería tener una buena idea de cuando omitir tipos y cuando explicitarlos. + +### Métodos sin argumentos + +Un pequeño problema de los métodos `re` e `im` es que para poder llamarlos es necesario agregar un par de paréntesis vacíos después de sus nombres, como muestra el siguiente ejemplo: + + object NumerosComplejos { def main(args: Array[String]) { - val c = new Complex(1.2, 3.4) - println("imaginary part: " + c.im()) + val c = new Complejo(1.2, 3.4) + println("Parte imaginaria: " + c.im()) } } -It would be nicer to be able to access the real and imaginary parts -like if they were fields, without putting the empty pair of -parenthesis. This is perfectly doable in Scala, simply by defining -them as methods *without arguments*. Such methods differ from -methods with zero arguments in that they don't have parenthesis after -their name, neither in their definition nor in their use. Our -`Complex` class can be rewritten as follows: +Sería mejor poder acceder las partes imaginarias y reales como si fueran campos, sin poner los paréntesis vacíos. Esto es perfectamente realizable en Scala, simplemente al definirlos como *métodos sin argumentos*. Tales métodos difieren de los métodos con cero o más argumentos en que no tienen paréntesis después de su nombre, tanto en la definición como en el uso. Nuestra clase `Complejo` puede ser reescrita así: - class Complex(real: Double, imaginary: Double) { + class Complejo(real: Double, imaginaria: Double) { def re = real - def im = imaginary + def im = imaginaria } -### Inheritance and overriding +### Herencia y sobreescritura -All classes in Scala inherit from a super-class. When no super-class -is specified, as in the `Complex` example of previous section, -`scala.AnyRef` is implicitly used. +Todas las clases en Scala heredan de una superclase. Cuando ninguna superclase es especificada, como es el caso de `Complejo` se utiliza implicitamente `scala.AnyRef`. -It is possible to override methods inherited from a super-class in -Scala. It is however mandatory to explicitly specify that a method -overrides another one using the `override` modifier, in order to -avoid accidental overriding. As an example, our `Complex` class -can be augmented with a redefinition of the `toString` method -inherited from `Object`. +Es posible sobreescribir métodos heredados de una superclase en Scala. Aunque es necesario explicitar específicamente que un método sobreescribe otro utilizando el modificador `override`, de manera de evitar sobreescrituras accidentales. Como ejemplo, nuestra clasee `Complejo` puede ser aumentada con la redefinición del método `toString` heredado de `Object`. - class Complex(real: Double, imaginary: Double) { + class Complejo(real: Double, imaginaria: Double) { def re = real - def im = imaginary - override def toString() = + def im = imaginaria + override def toString() = "" + re + (if (im < 0) "" else "+") + im + "i" } +## Clases Case y Reconocimiento de patrones -## Case Classes and Pattern Matching +Un tipo de estructura de datos uqe aparece seguido en programas es el Árbol. Por ejemplo, los intérpretes y compiladores usualmente representan los programas internamente como árboles; los documentos XML son árboles; y muchos otros tipos de contenedores están basados en árboles, como el árbol roji-negro (red-black tree). -A kind of data structure that often appears in programs is the tree. -For example, interpreters and compilers usually represent programs -internally as trees; XML documents are trees; and several kinds of -containers are based on trees, like red-black trees. +Ahora examinaremos cómo estos árboles son representados y manipulados en Scala mediante un pequeño programa que oficie de calculadora. El objetivo de este programa es manipular expresiones aritméticas simples compuestas de sumas de enteros y variables. Dos ejemplos de estas expresiones pueden ser: `1+2` y `(x+x)+(7+y)`. -We will now examine how such trees are represented and manipulated in -Scala through a small calculator program. The aim of this program is -to manipulate very simple arithmetic expressions composed of sums, -integer constants and variables. Two examples of such expressions are -`1+2` and `(x+x)+(7+y)`. - -We first have to decide on a representation for such expressions. The -most natural one is the tree, where nodes are operations (here, the -addition) and leaves are values (here constants or variables). +Primero tenemos que decidir una representación para tales expresiones. La más natural es un árbol, donde los nodos son las operaciones (la adición en este caso) y las hojas son valores (constantes o variables). In Java, such a tree would be represented using an abstract super-class for the trees, and one concrete sub-class per node or @@ -343,116 +220,66 @@ data-type for the same purpose. Scala provides the concept of *case classes* which is somewhat in between the two. Here is how they can be used to define the type of the trees for our example: - abstract class Tree - case class Sum(l: Tree, r: Tree) extends Tree - case class Var(n: String) extends Tree - case class Const(v: Int) extends Tree - -The fact that classes `Sum`, `Var` and `Const` are -declared as case classes means that they differ from standard classes -in several respects: - -- the `new` keyword is not mandatory to create instances of - these classes (i.e., one can write `Const(5)` instead of - `new Const(5)`), -- getter functions are automatically defined for the constructor - parameters (i.e., it is possible to get the value of the `v` - constructor parameter of some instance `c` of class - `Const` just by writing `c.v`), -- default definitions for methods `equals` and - `hashCode` are provided, which work on the *structure* of - the instances and not on their identity, -- a default definition for method `toString` is provided, and - prints the value in a "source form" (e.g., the tree for expression - `x+1` prints as `Sum(Var(x),Const(1))`), -- instances of these classes can be decomposed through - *pattern matching* as we will see below. - -Now that we have defined the data-type to represent our arithmetic -expressions, we can start defining operations to manipulate them. We -will start with a function to evaluate an expression in some -*environment*. The aim of the environment is to give values to -variables. For example, the expression `x+1` evaluated in an -environment which associates the value `5` to variable `x`, written -`{ x -> 5 }`, gives `6` as result. - -We therefore have to find a way to represent environments. We could of -course use some associative data-structure like a hash table, but we -can also directly use functions! An environment is really nothing more -than a function which associates a value to a (variable) name. The -environment `{ x -> 5 }` given above can simply be written as -follows in Scala: +En Java, un árbol así sería representado utilizando una superclase abstracta para los árboles, y una subclase concreta por nodo u hoja. En un lenguaje de programación funcional uno utilizaría un tipo de dato algebráico para el mismo propósito. Scala provee el concepto de *clases case* que está en el medio de los dos conceptos anteriores. Aquí mostramos como pueden ser usadas para definir el tipo de los árboles en nuestro ejemplo: + + abstract class Arbol + case class Sum(l: Arbol, r: Arbol) extends Arbol + case class Var(n: String) extends Arbol + case class Const(v: Int) extends Arbol + +El hecho de que las clases `Sum`, `Var` y `Const` sean declaradas como clases case significa que dififieren de las clases normales en varios aspectos: + +- no es obligatorio utilizar la palabra clave `new` para crear + instancias de estas clases (es decir, se puede escribir `Const(5)` + en lugar de `new Const(5)`), +- se crea automáticamente un "getter" (un método para obtener el valor) + para los parámetros utilizados en el constructor (por ejemplo es posible + obtener el valor de `v` de una instancia `c` de la clase `Const` de la + siguiente manera: `c.v`), +- se proveen definiciones por defecto de los métodos `equals` y `hashCode`, + que trabajan sobre la estructura de las instancias y no sobre su identidad, +- se crea una definición por defecto del método `toString` que + imprime el valor de una forma "tipo código) (ej: la expresión + del árbol `x+1` se imprimiría `Sum(Var(x),Const(1))`), +- las instancias de estas clases pueden ser descompuestas + mediante *reconocimiento de patrones* (pattern matching) + como veremos más abajo. + +Ahora que hemos definido el tipo de datos para representar nuestra expresión aritmética podemos empezar definiendo operaciones para manipularlas. Empezaremos con una función para evaluar una expresión en un *entorno*. El objetivo del entorno es darle valores a las variables. Por ejemplo, la expresión `x+1` evaluada en un entorno que asocia el valor `5` a la variable `x`, escrito `{ x -> 5 }`, da como resultado `6`. + +Por lo tanto tenemos que encontrar una manera de representar entornos. Podríamos por supuesto utilizar alguna estructura de datos asociativa como una tabla hash, pero podemos directamente utilizar funciones! Un entorno realmente no es nada más que una función la cual asocia valores a variables. El entorno `{ x -> 5 }` mostrado anteriormente puede ser fácilmente escrito de la siguiente manera en Scala: { case "x" => 5 } -This notation defines a function which, when given the string -`"x"` as argument, returns the integer `5`, and fails with an -exception otherwise. +Esta notación define una función la cual, dado un string `"x"` como argumento retorna el entero `5`, y falla con una excepción si no fuera así. -Before writing the evaluation function, let us give a name to the type -of the environments. We could of course always use the type -`String => Int` for environments, but it simplifies the program -if we introduce a name for this type, and makes future changes easier. -This is accomplished in Scala with the following notation: +Antes de escribir la función evaluadora, démosle un nombre al tipo de los entornos. Podríamos por supuesto simplemente utilizar `String => Int` para los entornos, pero simplifica el programa introducir un nombre para este tipo, y hace que los futuros cambios sean más fáciles. Esto lo realizamos de la siguiente manera: - type Environment = String => Int + type Entorno = String => Int -From then on, the type `Environment` can be used as an alias of -the type of functions from `String` to `Int`. +De ahora en más, el tipo `Entorno` puede ser usado como un alias del tipo de funciones definidas de `String` a `Int`. -We can now give the definition of the evaluation function. -Conceptually, it is very simple: the value of a sum of two expressions -is simply the sum of the value of these expressions; the value of a -variable is obtained directly from the environment; and the value of a -constant is the constant itself. Expressing this in Scala is not more -difficult: +Ahora podemos dar la definición de la función evaluadora. Conceptualmente, es muy sencillo: el valor de una suma de dos expresiones es simplemente la suma de los valores de estas expresiones; el valor de una variable es obtenido directamente del entorno; y eel valor de una constante es la constante en sí misma. Expresar esto en Scala no resulta para nada difícil: - def eval(t: Tree, env: Environment): Int = t match { - case Sum(l, r) => eval(l, env) + eval(r, env) - case Var(n) => env(n) + def eval(a: Arbol, ent: Entorno): Int = a match { + case Sum(i, d) => eval(i, ent) + eval(d, env) + case Var(n) => ent(n) case Const(v) => v } -This evaluation function works by performing *pattern matching* -on the tree `t`. Intuitively, the meaning of the above definition -should be clear: - -1. it first checks if the tree `t` is a `Sum`, and if it - is, it binds the left sub-tree to a new variable called `l` and - the right sub-tree to a variable called `r`, and then proceeds - with the evaluation of the expression following the arrow; this - expression can (and does) make use of the variables bound by the - pattern appearing on the left of the arrow, i.e., `l` and - `r`, -2. if the first check does not succeed, that is, if the tree is not - a `Sum`, it goes on and checks if `t` is a `Var`; if - it is, it binds the name contained in the `Var` node to a - variable `n` and proceeds with the right-hand expression, -3. if the second check also fails, that is if `t` is neither a - `Sum` nor a `Var`, it checks if it is a `Const`, and - if it is, it binds the value contained in the `Const` node to a - variable `v` and proceeds with the right-hand side, -4. finally, if all checks fail, an exception is raised to signal - the failure of the pattern matching expression; this could happen - here only if more sub-classes of `Tree` were declared. - -We see that the basic idea of pattern matching is to attempt to match -a value to a series of patterns, and as soon as a pattern matches, -extract and name various parts of the value, to finally evaluate some -code which typically makes use of these named parts. - -A seasoned object-oriented programmer might wonder why we did not -define `eval` as a *method* of class `Tree` and its -subclasses. We could have done it actually, since Scala allows method -definitions in case classes just like in normal classes. Deciding -whether to use pattern matching or methods is therefore a matter of -taste, but it also has important implications on extensibility: - -- when using methods, it is easy to add a new kind of node as this - can be done just by defining a sub-class of `Tree` for it; on - the other hand, adding a new operation to manipulate the tree is - tedious, as it requires modifications to all sub-classes of - `Tree`, +Esta función evaluadora función realizando un *reconocimiento de patrones* (pattern matching) en el árbol `a`. Intuitivamente, el significado de la definición de arriba debería estar claro: + +1. Primero comprueba si el árbol `t`es una `Sum`, y si lo es, asocia el sub-arbol izquierdo a una nueva variable llamada `i` y el sub-arbol derecho a la variable `r`, y después procede con la evaluación de la expresión que sigue a la flecha (`=>`); esta expresión puede (y hace) uso de las variables asociadas por el patrón que aparece del lado izquierdo de la flecha. +2. si la primer comprobación (la de `Sum`) no prospera, es decir que el árbol no es una `Sum`, sigue de largo y comprueba si `a` es un `Var`; si lo es, asocia el nombre contenido en el nodo `Var` a la variable `n` y procede con la parte derecha de la expresión. +3. si la segunda comprobación también falla, resulta que `a` no es un `Sum` ni un `Var`, por lo tanto comprueba que sea un `Const`, y si lo es, asocia el valor contenido en el nodo `Const` a la variable `v`y procede con el lado derecho. +4. finalmente, si todos las comprobaciones fallan, una excepción es lanzada para dar cuenta el fallo de la expresión; esto puede pasar solo si existen más subclases de `Arbol`. + +Hemos visto que la idea básica del reconocimiento de patrones es intentar coincidir un valor con una serie de patrones, y tan pronto como un patrón coincida, extraer y nombrar las varias partes del valor para finalmente evaluar algo de código que tipicamente hace uso de esas partes nombradas. + +Un programador con experiencia en orientación a objetos puede preguntarse por qué no definimos `eval` como un método de la clase `Arbol` y sus subclases. En realidad podríamos haberlo hecho, ya que Scala permite la definición de métodos en clases case tal como en clases normales. Por lo tanto decidir en usar reconocimiento de patrones o métodos es una cuestión de gustos, pero también tiene grandes implicancias en cuanto a la extensibilidad: + +- cuando usamos métodos, es fácil añadir un nuevo tipo de nodo ya que esto puede ser realizado simplemente al definir una nueva subclase de `Arbol`; por otro lado, añadir una nueva operación para manipular el árbol es tedioso, ya que requiere la modificación en todas las subclases. + - when using pattern matching, the situation is reversed: adding a new kind of node requires the modification of all functions which do pattern matching on the tree, to take the new node into account; on From 151cc36305aa35c4b725ad4bf6e9c6c481d2ca8b Mon Sep 17 00:00:00 2001 From: Santiago Basulto Date: Mon, 30 Jan 2012 22:58:20 -0300 Subject: [PATCH 3/5] Translating scala-for-java-programmers --- es/tutorials/scala-for-java-programmers.md | 69 ++++++++-------------- 1 file changed, 25 insertions(+), 44 deletions(-) diff --git a/es/tutorials/scala-for-java-programmers.md b/es/tutorials/scala-for-java-programmers.md index 06d433a7d8..970b48f365 100644 --- a/es/tutorials/scala-for-java-programmers.md +++ b/es/tutorials/scala-for-java-programmers.md @@ -280,71 +280,52 @@ Un programador con experiencia en orientación a objetos puede preguntarse por q - cuando usamos métodos, es fácil añadir un nuevo tipo de nodo ya que esto puede ser realizado simplemente al definir una nueva subclase de `Arbol`; por otro lado, añadir una nueva operación para manipular el árbol es tedioso, ya que requiere la modificación en todas las subclases. -- when using pattern matching, the situation is reversed: adding a - new kind of node requires the modification of all functions which do - pattern matching on the tree, to take the new node into account; on - the other hand, adding a new operation is easy, by just defining it - as an independent function. +- cuando utilizamos reconocimiento de patrones esta situación es inversa: agregar un nuevo tipo de nodo requiere la modificación de todas las funciones que hacen reconocimiento de patrones sobre el árbol, para tomar en cuenta un nuevo nodo; pero por otro lado agregar una nueva operación fácil, solamente definiendolo como una función independiente. To explore pattern matching further, let us define another operation on arithmetic expressions: symbolic derivation. The reader might remember the following rules regarding this operation: -1. the derivative of a sum is the sum of the derivatives, -2. the derivative of some variable `v` is one if `v` is the - variable relative to which the derivation takes place, and zero - otherwise, -3. the derivative of a constant is zero. +Para explorar un poco más esto de pattern matching definamos otra operación aritmética: derivación simbólica. El lector recordará las siguientes reglas sobre esta operación: + +1. la derivada de una suma es la suma de las derivadas, +2. la derivada de una variable `v` es uno (1) si `v` es la variable relativa a la cual la derivada toma lugar, y cero (0)de otra manera, +3. la derivada de una constante es cero (0). These rules can be translated almost literally into Scala code, to obtain the following definition: - def derive(t: Tree, v: String): Tree = t match { - case Sum(l, r) => Sum(derive(l, v), derive(r, v)) +Estas reglas pueden ser traducidas casi literalmente en código Sclaa, para obtener la siguiente definición. + + def derivada(a: Arbol, v: String): Arbol = a match { + case Sum(l, r) => Sum(derivada(l, v), derivada(r, v)) case Var(n) if (v == n) => Const(1) case _ => Const(0) } -This function introduces two new concepts related to pattern matching. -First of all, the `case` expression for variables has a -*guard*, an expression following the `if` keyword. This -guard prevents pattern matching from succeeding unless its expression -is true. Here it is used to make sure that we return the constant `1` -only if the name of the variable being derived is the same as the -derivation variable `v`. The second new feature of pattern -matching used here is the *wildcard*, written `_`, which is -a pattern matching any value, without giving it a name. - -We did not explore the whole power of pattern matching yet, but we -will stop here in order to keep this document short. We still want to -see how the two functions above perform on a real example. For that -purpose, let's write a simple `main` function which performs -several operations on the expression `(x+x)+(7+y)`: it first computes -its value in the environment `{ x -> 5, y -> 7 }`, then -computes its derivative relative to `x` and then `y`. +Esta función introduce dos nuevos conceptos relacionados al pattern matching. Primero que nada la expresión `case` para variables tienen una *guarda*, una expresión siguiendo la palabra clave `if`. Esta guarda previene que el patrón concuerde al menos que la expresión sea verdadera. Aquí es usada para asegurarse que retornamos la constante 1 solo si el nombre de la variable siendo derivada es el mismo que la variable derivada `v`. El segundo concepto nuevo usado aquí es el *comodín*, escrito con el guión bajo `_`, que coincide con cualquier valor que aparezca, sin darle un nombre. + +No hemos explorado el completo poder del pattern matching aún, pero nos detendremos aquí para mantener este documento corto. Todavía nos queda pendiente ver cómo funcionan las dos funciones de arriba en un ejemplo real. Para ese propósito, escribamos una función main simple que realice algunas operaciones sobre la expresión `(x+x)+(7+y)`: primero computa su valor en el entorno `{ x -> 5, y -> 7 }` y después computa su derivada con respecto a `x` y después a `y`. def main(args: Array[String]) { - val exp: Tree = Sum(Sum(Var("x"),Var("x")),Sum(Const(7),Var("y"))) - val env: Environment = { case "x" => 5 case "y" => 7 } - println("Expression: " + exp) - println("Evaluation with x=5, y=7: " + eval(exp, env)) - println("Derivative relative to x:\n " + derive(exp, "x")) - println("Derivative relative to y:\n " + derive(exp, "y")) + val exp: Arbol = Sum(Sum(Var("x"),Var("x")),Sum(Const(7),Var("y"))) + val ent: Entonrno = { case "x" => 5 case "y" => 7 } + println("Expresión: " + exp) + println("Evaluación con x=5, y=7: " + eval(exp, ent)) + println("Derivada con respecto a x:\n " + derivada(exp, "x")) + println("Derivada con respecto a y:\n " + derivada(exp, "y")) } -Executing this program, we get the expected output: +Al ejecutar este programa obtenemos el siguiente resultado: - Expression: Sum(Sum(Var(x),Var(x)),Sum(Const(7),Var(y))) - Evaluation with x=5, y=7: 24 - Derivative relative to x: + Expresión: Sum(Sum(Var(x),Var(x)),Sum(Const(7),Var(y))) + Evaluación con x=5, y=7: 24 + Derivada con respecto a x: Sum(Sum(Const(1),Const(1)),Sum(Const(0),Const(0))) - Derivative relative to y: + Derivada con respecto a y: Sum(Sum(Const(0),Const(0)),Sum(Const(0),Const(1))) -By examining the output, we see that the result of the derivative -should be simplified before being presented to the user. Defining a -basic simplification function using pattern matching is an interesting -(but surprisingly tricky) problem, left as an exercise for the reader. +Al examinar la salida vemos que el resultado de la derivada debería ser simplificado antes de ser presentado al usuario. Definir una función de simplificación básica utilizando reconocimiento de patrones es un problema interesante (y, por no decir complejo, que necesita una solución astuta), lo dejamos para un ejercicio para el lector. ## Traits From d814745f00233525a1bd47f7a8efb16c100cb08d Mon Sep 17 00:00:00 2001 From: Santiago Basulto Date: Sat, 4 Feb 2012 17:34:16 -0300 Subject: [PATCH 4/5] Translated scala-for-java-programmers --- es/tutorials/scala-for-java-programmers.md | 197 +++++++-------------- 1 file changed, 63 insertions(+), 134 deletions(-) diff --git a/es/tutorials/scala-for-java-programmers.md b/es/tutorials/scala-for-java-programmers.md index 970b48f365..b38f9fc6a2 100644 --- a/es/tutorials/scala-for-java-programmers.md +++ b/es/tutorials/scala-for-java-programmers.md @@ -329,29 +329,15 @@ Al examinar la salida vemos que el resultado de la derivada debería ser simplif ## Traits -Apart from inheriting code from a super-class, a Scala class can also -import code from one or several *traits*. - -Maybe the easiest way for a Java programmer to understand what traits -are is to view them as interfaces which can also contain code. In -Scala, when a class inherits from a trait, it implements that trait's -interface, and inherits all the code contained in the trait. - -To see the usefulness of traits, let's look at a classical example: -ordered objects. It is often useful to be able to compare objects of a -given class among themselves, for example to sort them. In Java, -objects which are comparable implement the `Comparable` -interface. In Scala, we can do a bit better than in Java by defining -our equivalent of `Comparable` as a trait, which we will call -`Ord`. - -When comparing objects, six different predicates can be useful: -smaller, smaller or equal, equal, not equal, greater or equal, and -greater. However, defining all of them is fastidious, especially since -four out of these six can be expressed using the remaining two. That -is, given the equal and smaller predicates (for example), one can -express the other ones. In Scala, all these observations can be -nicely captured by the following trait declaration: +_Nota: La palabra Trait(/treɪt/, pronunciado Treit) puede ser traducida literalmente como "Rasgo". De todas maneras decido utilizar la notación original por ser un concepto muy arraigado a Scala_ + +Aparte de poder heredar código de una super clase, una clase en Scala puede también importar código de uno o varios *traits*. + +Tal vez la forma más fácil para un programador Java de entender qué son los traits es verlos como interfaces que también pueden contener código. En Scala, cuando una clase hereda de un trait, implementa la interface de ese trait, y hereda todo el código contenido en el trait. + +Para ver la utilidad de los traits, veamos un ejemplo clásico: objetos ordenados. Generalemente es útil tener la posibilidad de comparar objetos de una clase dada entre ellos, por ejemplo, para ordenarlos. En Java, los objetos que son comparables implementan la interfaz `Comparable`. En Scala, podemos hacer algo un poco mejor que en Java al definir un trait equivalente `Comparable` que invocará a `Ord`. + +Cuando comparamos objetos podemos utilizar seis predicados distintos: menor, menor o igual, igual, distinto, mayor o igual y mayor. De todas maneras, definir todos estos es fastidioso, especialmente que cuatro de estos pueden ser expresados en base a los otros dos. Esto es, dados los predicados "igual" y "menor" (por ejemplo), uno puede expresar los otros. En Scala, todas estas observaciones pueden ser fácilmente capturadas mediante la siguiente declaración de un Trait: trait Ord { def < (that: Any): Boolean @@ -360,16 +346,9 @@ nicely captured by the following trait declaration: def >=(that: Any): Boolean = !(this < that) } -This definition both creates a new type called `Ord`, which -plays the same role as Java's `Comparable` interface, and -default implementations of three predicates in terms of a fourth, -abstract one. The predicates for equality and inequality do not appear -here since they are by default present in all objects. +Esta definición crea un nuevo tipo llamado `Ord` el cual juega el mismo rol que la interfaz `Comparable`, como también provee implementaciones de tres predicados en términos de un cuarto, abstracto. Los predicados para igualidad y su inverso (distinto, no igual) no aparecen aquí ya que por defecto están presenten en todos los objetos. -The type `Any` which is used above is the type which is a -super-type of all other types in Scala. It can be seen as a more -general version of Java's `Object` type, since it is also a -super-type of basic types like `Int`, `Float`, etc. +El tipo `Any` el cual es usado arriba es el supertipo de todos los otros tipos en Scala. Puede ser visto como una versión más general del tipo `Object` en Java, ya que `Any` también es supertipo de `Int`, `Float`, etc. cosa que no se cumple en Java (`int` por ejemplo es un tipo primitivo). To make objects of a class comparable, it is therefore sufficient to define the predicates which test equality and inferiority, and mix in @@ -379,128 +358,78 @@ dates are composed of a day, a month and a year, which we will all represent as integers. We therefore start the definition of the `Date` class as follows: - class Date(y: Int, m: Int, d: Int) extends Ord { - def year = y - def month = m - def day = d - override def toString(): String = year + "-" + month + "-" + day +Para hacer a un objeto de la clase comparable es suficiente definir los predicados que comprueban la igualdad y la inferioridad y mezclar la clase `Ord` de arriba. Como un ejemplo, definamos una clase `Fecha` que representa fechas en el calendario gregoriano. -The important part here is the `extends Ord` declaration which -follows the class name and parameters. It declares that the -`Date` class inherits from the `Ord` trait. + class Fecha(d: Int, m: Int, a: Int) extends Ord { + def anno = a + def mes = m + def dia = d + override def toString(): String = anno + "-" + mes + "-" + dia -Then, we redefine the `equals` method, inherited from -`Object`, so that it correctly compares dates by comparing their -individual fields. The default implementation of `equals` is not -usable, because as in Java it compares objects physically. We arrive -at the following definition: +La parte importante aquí es la declaración `extends Ord` la cual sigue al nombre de la clase y los parámetros. Declara que la clase `Fecha` hereda del trait `Ord`. + +Después redefinimos el método `equals`, heredado de `Object`, para comparar correctamente fechas mediante sus campos individuales. La implementación por defecto de `equals` no es utilizable, porque como en Java, compara los objetos fisicamente. Por lo tanto llegamos a esto: override def equals(that: Any): Boolean = - that.isInstanceOf[Date] && { - val o = that.asInstanceOf[Date] - o.day == day && o.month == month && o.year == year + that.isInstanceOf[Fecha] && { + val o = that.asInstanceOf[Fecha] + o.dia== dia && o.mes == mes && o.anno== anno } -This method makes use of the predefined methods `isInstanceOf` -and `asInstanceOf`. The first one, `isInstanceOf`, -corresponds to Java's `instanceof` operator, and returns true -if and only if the object on which it is applied is an instance of the -given type. The second one, `asInstanceOf`, corresponds to -Java's cast operator: if the object is an instance of the given type, -it is viewed as such, otherwise a `ClassCastException` is -thrown. +Este método utiliza el método predefinido `isInstanceOf` ("es instancia de") y `asInstanceOf` ("como instancia de"). El primero `isInstanceOf` se corresponde con el operador java `instanceOf` y retorna `true` si y solo si el objeto en el cual es aplicado es una instancia del tipo dado. El segundo, `asInstanceOf`, corresponde al operador de casteo en Java: si el objeto es una instancia de un tipo dado, esta es vista como tal, de otra manera se lanza una excepción `ClassCastException`. -Finally, the last method to define is the predicate which tests for -inferiority, as follows. It makes use of another predefined method, -`error`, which throws an exception with the given error message. +Finalmente el último método para definir es el predicado que comprueba la inferioridad. Este hace uso de otro método predefinido, `error` que lanza una escepción con el mensaje de error provisto. def <(that: Any): Boolean = { - if (!that.isInstanceOf[Date]) - error("cannot compare " + that + " and a Date") + if (!that.isInstanceOf[Fecha]) + error("no se puede comparar" + that + " y una fecha") - val o = that.asInstanceOf[Date] - (year < o.year) || - (year == o.year && (month < o.month || - (month == o.month && day < o.day))) + val o = that.asInstanceOf[Fecha] + (anno < o.anno) || + (anno== o.anno && (mes < o.mes || + (mes == o.mes && dia < o.dia))) } -This completes the definition of the `Date` class. Instances of -this class can be seen either as dates or as comparable objects. -Moreover, they all define the six comparison predicates mentioned -above: `equals` and `<` because they appear directly in -the definition of the `Date` class, and the others because they -are inherited from the `Ord` trait. - -Traits are useful in other situations than the one shown here, of -course, but discussing their applications in length is outside the -scope of this document. - -## Genericity - -The last characteristic of Scala we will explore in this tutorial is -genericity. Java programmers should be well aware of the problems -posed by the lack of genericity in their language, a shortcoming which -is addressed in Java 1.5. - -Genericity is the ability to write code parametrized by types. For -example, a programmer writing a library for linked lists faces the -problem of deciding which type to give to the elements of the list. -Since this list is meant to be used in many different contexts, it is -not possible to decide that the type of the elements has to be, say, -`Int`. This would be completely arbitrary and overly -restrictive. - -Java programmers resort to using `Object`, which is the -super-type of all objects. This solution is however far from being -ideal, since it doesn't work for basic types (`int`, -`long`, `float`, etc.) and it implies that a lot of -dynamic type casts have to be inserted by the programmer. - -Scala makes it possible to define generic classes (and methods) to -solve this problem. Let us examine this with an example of the -simplest container class possible: a reference, which can either be -empty or point to an object of some type. - - class Reference[T] { - private var contents: T = _ - def set(value: T) { contents = value } - def get: T = contents +Esto completa la definición de la clase `Fecha`. Las instancias de esta clase pueden ser vistas tanto como fechas o como objetos comparables. Además, todas ellas definen los seis predicados de comparación mencionados arriba: `equals` y `<` porque aparecen directamente en la definición de la clase `Fecha` y los otros porque son heredados del trait `Ord`. + +Los traits son útiles en muchas otras más situaciones que las aquí mostrada, pero discutir sus aplicaciones está fuera del alcance de este documento. + +## Tipos Genéricos + +_Nota: El diseñador de los tipos genéricos en Java fue nada más ni nada menos que Martin Odersky, el diseñador de Scala._ + +La última característica de Scala que exploraremos en este tutorial es la de los tipos genéricos. Los programadores de Java deben estar bien al tanto de los problemas que genera la falta de genéricos en su lenguaje, lo cual es solucionado en Java 1.5. + +Los tipos genéricos proveen al programador la habilidad de escribir código parametrizado por tipos. Por ejemplo, escribir una librería para listas enlazadas se enfrenta al problema de decidir qué tipo darle a los elementos de la lista. Ya que esta lista está pensada para ser usada en diferentes contextos, no es posible decidir que el tipo de elementos sea, digamos, `Int`. Esto sería completamente arbitrario y muy restrictivo. + +Los programadores Java cuentan como último recurso con `Object`, que es el supertipo de todos los objetos. Esta solución de todas maneras está lejos de ser ideal, ya que no funciona con tipos primitivos (`int`, `long`, `float`, etc.) e implica que el programador tenga que realizar muchos casteos de tipos en su programa. + +Scala hace posible definir clases genéricas (y métodos) para resolver este problema. Examinemos esto con un ejemplo del contenedor más simple posible: una referencia, que puede estar tanto vacía como apuntar a un objeto de algún tipo. + + class Referencia[T] { + private var contenido: T = _ + def set(valor: T) { contenido = valor } + def get: T = contenido } -The class `Reference` is parametrized by a type, called `T`, -which is the type of its element. This type is used in the body of the -class as the type of the `contents` variable, the argument of -the `set` method, and the return type of the `get` method. +La clase `Referencia` es parametrizada por un tipo llamado `T`, que es el tipo de sus elementos. Este tipo es usado en el cuerpo de la clase como el tipo de la variable `contenido`, el argumento del método `set` y el tipo de retorno del método `get`. -The above code sample introduces variables in Scala, which should not -require further explanations. It is however interesting to see that -the initial value given to that variable is `_`, which represents -a default value. This default value is 0 for numeric types, -`false` for the `Boolean` type, `()` for the `Unit` -type and `null` for all object types. +El ejemplo anterior introduce a las variables en Scala, que no deberían requerir mayor explicación. Es interesante notar que el valor inicial dado a la variable `contenido` es `_`, que representa un valor por defecto. Este valor por defecto es 0 para tipos numéricos, `false` para tipos `Boolean`, `()` para el tipo `Unit` y `null` para el resto de los objetos. -To use this `Reference` class, one needs to specify which type to use -for the type parameter `T`, that is the type of the element -contained by the cell. For example, to create and use a cell holding -an integer, one could write the following: +Para utilizar esta clase `Referencia`, uno necesita especificar qué tipo utilizar por el parámetro `T`, es decir, el tipo del elemento contenido por la referencia. Por ejemplo, para crear y utilizar una referencia que contenga un entero, podríamos escribir lo siguiente: - object IntegerReference { + object ReferenciaEntero { def main(args: Array[String]) { - val cell = new Reference[Int] - cell.set(13) - println("Reference contains the half of " + (cell.get * 2)) + val ref = new Referencia[Int] + ref.set(13) + println("La referncia tiene la mitad de " + (ref.get * 2)) } } -As can be seen in that example, it is not necessary to cast the value -returned by the `get` method before using it as an integer. It -is also not possible to store anything but an integer in that -particular cell, since it was declared as holding an integer. +Como puede verse en el ejemplo, no es necesario castear el valor retornado por el método `get` antes de usarlo como un entero. Tampoco es posible almacenar otra cosa que no sea un entero en esa referencia en particular, ya que fue declarada como contenedora de un entero. -## Conclusion +## Conclusión -This document gave a quick overview of the Scala language and -presented some basic examples. The interested reader can go on, for example, by -reading the document *Scala By Example*, which -contains much more advanced examples, and consult the *Scala - Language Specification* when needed. +Scala es un lenguaje tremendamente poderoso que ha sabido heredar las mejores cosas de cada uno de los lenguajes más exitosos que se han conocido. Java no es la excepción, y comparte muchas cosas con este. La diferencia que vemos es que para cada uno de los conceptos de Java, Scala los aumenta, refina y mejora. Poder aprender todas las características de Scala nos equipa con más y mejores herramientas a la hora de escribir nuestros programas. +Si bien la programación funcional no ha sido una característica de Java, el progamador experimentado puede notar la falta de soporte de este paradigma en múltiples ocasiones. El solo pensar en el código necesario para proveer a un `JButton` con el código que debe ejecutar al ser presionado nos muestra lo necesario que sería contar con herramientas funcionales. Recomendamos entonces tratar de ir incorporando estas características, por más que sea difícil para el programador Java al estar tan acostumbrado al paradigma imperativo de este lenguaje. +Este documento dio una rápida introducción al lenguaje Scala y presento algunos ejemplos básicos. El lector interesado puede seguir, por ejemplo, leyendo el *Tutorial de Scala* que figura en el sitio de documentación, o *Scala by Example* (en inglés). También puede consultar la especificación del lenguaje cuando lo desee. From a84be998a72c4f67434bf84103bf72f64699f2e3 Mon Sep 17 00:00:00 2001 From: Santiago Basulto Date: Sat, 4 Feb 2012 19:06:27 -0300 Subject: [PATCH 5/5] Bug fixes on scala-for-java-programmers --- es/tutorials/scala-for-java-programmers.md | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/es/tutorials/scala-for-java-programmers.md b/es/tutorials/scala-for-java-programmers.md index b38f9fc6a2..1bf2ea9c08 100644 --- a/es/tutorials/scala-for-java-programmers.md +++ b/es/tutorials/scala-for-java-programmers.md @@ -91,7 +91,7 @@ Para concluir esta sección sobre la interacción con Java, es importante notar Scala es un lenguaje puramente orientado a objetos en el sentido de que *todo* es un objeto, incluyendo números o funciones. Difiere de Java en este aspecto, ya que Java distingue tipos primitivos (como `boolean` e `int`) de tipos referencialbes, y no nos permite manipular las funciones como valores. -### Numbers are objects +### Los números son objetos Ya que los números son objetos, estos también tienen métodos. De hecho, una expresión aritmética como la siguiente: @@ -213,13 +213,6 @@ Ahora examinaremos cómo estos árboles son representados y manipulados en Scala Primero tenemos que decidir una representación para tales expresiones. La más natural es un árbol, donde los nodos son las operaciones (la adición en este caso) y las hojas son valores (constantes o variables). -In Java, such a tree would be represented using an abstract -super-class for the trees, and one concrete sub-class per node or -leaf. In a functional programming language, one would use an algebraic -data-type for the same purpose. Scala provides the concept of -*case classes* which is somewhat in between the two. Here is how -they can be used to define the type of the trees for our example: - En Java, un árbol así sería representado utilizando una superclase abstracta para los árboles, y una subclase concreta por nodo u hoja. En un lenguaje de programación funcional uno utilizaría un tipo de dato algebráico para el mismo propósito. Scala provee el concepto de *clases case* que está en el medio de los dos conceptos anteriores. Aquí mostramos como pueden ser usadas para definir el tipo de los árboles en nuestro ejemplo: abstract class Arbol @@ -350,14 +343,6 @@ Esta definición crea un nuevo tipo llamado `Ord` el cual juega el mismo rol que El tipo `Any` el cual es usado arriba es el supertipo de todos los otros tipos en Scala. Puede ser visto como una versión más general del tipo `Object` en Java, ya que `Any` también es supertipo de `Int`, `Float`, etc. cosa que no se cumple en Java (`int` por ejemplo es un tipo primitivo). -To make objects of a class comparable, it is therefore sufficient to -define the predicates which test equality and inferiority, and mix in -the `Ord` class above. As an example, let's define a -`Date` class representing dates in the Gregorian calendar. Such -dates are composed of a day, a month and a year, which we will all -represent as integers. We therefore start the definition of the -`Date` class as follows: - Para hacer a un objeto de la clase comparable es suficiente definir los predicados que comprueban la igualdad y la inferioridad y mezclar la clase `Ord` de arriba. Como un ejemplo, definamos una clase `Fecha` que representa fechas en el calendario gregoriano. class Fecha(d: Int, m: Int, a: Int) extends Ord { @@ -432,4 +417,5 @@ Como puede verse en el ejemplo, no es necesario castear el valor retornado por e Scala es un lenguaje tremendamente poderoso que ha sabido heredar las mejores cosas de cada uno de los lenguajes más exitosos que se han conocido. Java no es la excepción, y comparte muchas cosas con este. La diferencia que vemos es que para cada uno de los conceptos de Java, Scala los aumenta, refina y mejora. Poder aprender todas las características de Scala nos equipa con más y mejores herramientas a la hora de escribir nuestros programas. Si bien la programación funcional no ha sido una característica de Java, el progamador experimentado puede notar la falta de soporte de este paradigma en múltiples ocasiones. El solo pensar en el código necesario para proveer a un `JButton` con el código que debe ejecutar al ser presionado nos muestra lo necesario que sería contar con herramientas funcionales. Recomendamos entonces tratar de ir incorporando estas características, por más que sea difícil para el programador Java al estar tan acostumbrado al paradigma imperativo de este lenguaje. + Este documento dio una rápida introducción al lenguaje Scala y presento algunos ejemplos básicos. El lector interesado puede seguir, por ejemplo, leyendo el *Tutorial de Scala* que figura en el sitio de documentación, o *Scala by Example* (en inglés). También puede consultar la especificación del lenguaje cuando lo desee.