Scala: Introducción y Conceptos Básicos

Última actualización: 05/01/2023

En esta entrada aprenderás los conceptos básicos del lenguaje de programación Scala. Está orientado a principiantes y cubriré los fundamentos para que conozcas el lenguaje y puedas empezar a trabajar con él en tus proyectos.

Scala - Introducción y conceptos básicos

¿Qué es Scala?

Scala es un lenguaje de programación de propósito general creado en el año 2004 que soporta programación funcional y orientada a objetos. El código se compila y ejecuta en la máquina virtual de Java (JVM). Scala está muy ligado a Java, con el que tiene interoperabilidad y es posible usar librerías de ambos lenguajes en la misma aplicación.

Scala es un lenguaje muy popular en el sector del big data y de aplicaciones distribuidas. Algunas de las herramientas más populares como el framework de procesamiento distribuido Apache Spark están desarrolladas en el lenguaje de programación Scala. Esta es la razón por la que se suele encontrar a Scala en lo alto de las listas de habilidades más demandadas para ingenieros de datos.

Scala REPL

Scala proporciona también un intérprete por línea de comandos o REPL (Read-Evaluate-Print-Loop). Esta herramienta es muy útil para evaluar expresiones fácilmente y probar nuestro código. Entre sus funcionalidades se encuentra el autocompletado.

Puedes descargar Scala de la web oficial.

Para ejecutar la REPL, escribiremos en una terminal de tu sistema operativo scala:

$ scala
Welcome to Scala version 2.10.6 (OpenJDK 64-Bit Server VM, Java 1.8.0_292).
Type in expressions to have them evaluated.
Type :help for more information.

scala>

Puedes cerrarla usando el comando «:q»

Ahora, ya estás listo para escribir expresiones. Vamos a empezar con algunos conceptos básicos de este lenguaje y su sintaxis.

Valores y Variables

En escala se trabaja con valores o values, que definen constantes. La palabra reservada val indica que este valor es inmutable y no se podrá modificar ni reasignar valores después de su creación.

scala> val edad: Int = 20
edad: Int = 20

scala> edad = 21
<console>:8: error: reassignment to val
       edad = 21
            ^

En este ejemplo, intento reasignar un valor a una constante llamada edad. Como vemos, nos da un error.

Para hacer un valor variable en Scala deberemos usar el modificador var. Reasignar valores de esta forma sí que está permitido.

scala> var edad: Int = 20
edad: Int = 20

scala> edad = 21
edad: Int = 21

Scala es un lenguaje en el que no necesitaremos especificar los tipos de nuestros valores. El compilador puede inferirlo del valor que le asignamos. Aún así, también podemos especificarlo si deseamos que sea explícito, como en los ejemplos anteriores.

scala> var edad = 21
edad: Int = 21

En este ejemplo, vemos que nos infiere directamente el tipo Int sin haberle especificado en el momento de creación ningún tipo de datos.

Cadenas (Strings)

La creación y manipulación de Strings o cadenas funciona de forma muy similar a otros lenguajes como Java. Usaremos comillas para delimitarlos y podremos concatenarlos fácilmente usando el símbolo +

scala> val cadena = "Hola mundo"
cadena: String = Hola mundo

scala> val cadena2 = "Hola " + "mundo"
cadena2: String = Hola mundo

scala> cadena2.length
res0: Int = 10

Para intercalar una variable o constante dentro de una cadena podemos usar s (string interpolator). El valor se puede usar mediante el símbolo $

scala> val hola = "Hola"
hola: String = Hola

scala> println(s"$hola mundo")
Hola mundo

Aquí, vemos también que la función println nos permite imprimir por pantalla el resultado de las expresiones.

Expresiones

Cuando hablamos de expresiones en scala, nos referimos a estructuras de código que pueden ser reducidas a un valor. Por ejemplo una expresión puede ser un cálculo o una llamada a una función. Las expresiones pueden formar un bloque, que irá entre llaves. Este bloque, puede contener variables locales. La última expresión del bloque se corresponderá con el valor de retorno del bloque:

scala> val resultado = {val a = 10 + 1; if (a > 1) a else 0}
resultado: Int = 11

En este código, vemos que nuestro bloque está formado por dos expresiones. Por un lado, vemos que el valor de a es local a este bloque y que se usa en una estructura de tipo if-else en el segundo bloque para determinar el valor de retorno.

Funciones en Scala

Como en otros lenguajes funcionales, las funciones en Scala son un tipo de objeto que se pueden asignar a variables. Se llaman métodos a las definiciones que forman parte de una clase y que tienen un nombre y una estructura. Podemos definir una función de la siguiente forma:

scala> def factorial(n: Int): Int = {
     | if(n < 1) 1
     | else n * factorial(n - 1)
     | }
factorial: (n: Int)Int

scala> factorial(10)
res1: Int = 3628800

Aquí, vemos que para definir una función usaremos el término def. También, especificaremos en la definición el nombre de la función, los argumentos, el tipo de los argumentos y el tipo de datos que devuelve la función. En este caso, estamos definiendo la función factorial, que es una función recursiva (se llama a sí misma). En Scala es muy común usar la recursión en vez de bucles.

Una función no tiene por qué devolver un valor. En el caso de que no queramos que devuelva ningún valor, especificaremos el tipo de retorno Unit. Este es equivalente a void en Java:

scala> def imprimir(cadena: String): Unit = {
     | println(s"tu cadena es $cadena")
     | }
imprimir: (cadena: String)Unit

scala> imprimir("hola")
tu cadena es hola

El lenguaje también soporta funciones anónimas y anidadas.

Clases en Scala

Scala también nos permite definir clases para crear nuestros objetos. Las clases pueden contener valores, variables, métodos y traits. El acceso a los métodos y a los campos de una clase se realiza con el símbolo punto (.) como en otros lenguajes como Java.

Los métodos y campos de las clases son públicos por defecto. Podemos establecer su visibilidad con los modificadores private y protected. Ahora, vamos a ver un ejemplo de definición de una clase sencilla. Con un método y un campo o atributo:

scala> class Vehiculo {
     | val color: String = "Blanco"
     | def arrancar() = println("Vehiculo arrancado")
     | }
defined class Vehiculo

scala> val coche = new Vehiculo
coche: Vehiculo = [email protected]

scala> coche.arrancar()
Vehiculo arrancado

scala> coche.color
res2: String = Blanco

Para definir una nueva clase, usaremos la palabra reservada class. Para crear nuevos objetos de una clase, usaremos la palabra reservada new.

Las clases en Scala también pueden tener argumentos de su constructor. Por ejemplo, si ampliamos el ejemplo anterior, podemos hacer que el constructor tome un argumento:

scala> class Vehiculo(val color: String)
defined class Vehiculo

scala> val v = new Vehiculo("Rojo")
v: Vehiculo = [email protected]

scala> v.color
res0: String = Rojo

Lazy en scala indica que no evalúe el método o esa variable hasta que no sea necesario.

la Annotation @tailrec en scala permite hacer a una función recursiva iterativa, para evitar errores stack overflow.

Herencia en Scala

Para implementar herencia de clases usamos el término extends. En este ejemplo, tomamos la definición de la clase Vehículo que hicimos antes y creamos una clase Coche que la extiende. Como podemos ver, podemos hacer uso de los métodos y campos de su clase padre.

scala> class Vehiculo {
     | val color: String = "Blanco"
     | def arrancar() = println("Vehiculo arrancado")
     | }
defined class Vehiculo

scala> class Coche extends Vehiculo {
     | val id: Int = 1
     | }
defined class Coche

scala> val c = new Coche()
c: Coche = [email protected]

scala> c.color
res1: String = Blanco

scala> c.arrancar()
Vehiculo arrancado

Cuando una clase extiende de otra, hereda todos los métodos y campos no privados.

Clases Abstractas

Las clases abstractas pueden implementar métodos abstractos y no abstractos, no pueden instanciarse y no soportan herencia múltiple. Para hacer una clase abstracta usamos el término abstract.

Es obligatorio que la clase hijo implemente todos los métodos abstractos (los que no contienen ninguna implementación) de la clase padre.

scala> abstract class Vehiculo {
     | def numRuedas(): Int
     | }
defined class Vehiculo

scala> class Coche extends Vehiculo {
     | def numRuedas(): Int = {
     | 4
     | }
     | }
defined class Coche

scala> val c = new Coche()
c: Coche = [email protected]

scala> c.numRuedas
res3: Int = 4

Traits

Los Traits de Scala son como las Interfaces parcialmente implementadas en Java. No se pueden instanciar ni tienen parámetros. Las clases y objetos de Scala pueden extender uno o varios Traits (al contrario que la herencia en Java que deja solo un padre).

Podemos definir un Trait de la siguiente forma:

scala> trait Imprimir {
     | def hola(): Unit = {
     | println("hola")
     | }
     | def saludo(): Unit
     | }
defined trait Imprimir

scala> class Test extends Imprimir {
     | def saludo(): Unit = {
     | println("saludo")
     | }
     | }
defined class Test

scala> val t = new Test()
t: Test = [email protected]

scala> t.hola
hola

scala> t.saludo 
saludo

Los traits deben contener al menos un método abstracto sin implementar. Cuando una clase implementa varios Traits y dos de ellos hacen override de la misma función llamando a super se aplican los dos, de derecha a izquierda.

Singleton en Scala

En Scala no existe static como en Java. Para definir una clase de la que solamente existe una instancia se usan los objetos con la palabra reservada object. Los métodos y campos dentro de este objeto se pueden importar globalmente. Los objetos pueden extender clases y Traits y actúa como el punto de entrada de las aplicaciones.

Siguientes Pasos y Formación en Scala

En este artículo, también puedes aprender sobre cómo hacer un proyecto en Scala en el IDE IntelliJ y con el gestor de dependencias SBT

Te recomiendo el siguiente curso para aprender Scala a fondo, de los mejores que encontrarás. Lo podrás completar al ritmo que quieras para aprender todos los conceptos que necesitarás para desenvolverte con Scala profesionalmente: una habilidad fundamental para cualquier ingeniero o científico de datos.

Preguntas Frecuentes Scala – FAQ

¿Por qué debería aprender Scala?

Scala es un lenguaje de programación moderno, compatible con Java y que se usa en multitud de proyectos Big Data o en aplicaciones distribuidas como Apache Spark o Akka. Esto se debe a sus capacidades de concurrencia y facilidad de paralelismo.

¿Cuáles son las ventajas de Scala?

Scala es un lenguaje más flexible y fácil de mantener que otras opciones debido a su naturaleza funcional y orientación a objetos. Además, es posible incluir librerías de Java en tus aplicaciones.


Deja una respuesta