Feeds:
Posts
Comments

Scala first steps

I thought that Java would have been my last programming language, but Scala came and I love it!

I tried some dynamic languages like Ruby and was, at a certain point in time, inclined to drop the static typing that I believed so much in, for the conciseness and flexibility of such languages.

But with Scala you don’t have to sacrify anything. You may have the best of both worlds !

In this series of posts, I’ll try, through a small example, to show the flexibility, conciseness and elegancy of this nice language. At the same time, I will demonstrate the Scala way of handling a kind of “multiple inheritance”, without the drawbacks that this technique usually implies.

I will use the insurance business domain as base of this example. Of course, it will not be representative of a real business problem but hopefully will permit to illustrate some of the most pleasant and powerfull features of Scala.

I assume the reader have a good understanding of OO concepts and a working experience with Java, as Scala will be presented as the future of Java or a “better Java”. But no previous exposure to functional programming is required as I will introduce the basic concepts as needed.

The goal is not to teach a complete Scala course but to give you the taste of it. Then if you like it, buy Martin Odersky’s book and learn it in depth, it is worth the effort !

So, let’s start by writing of few lines of code.

Suppose we want to represent an insurance product, with some characteristics, like insurance amount, deductible, premium rate, etc. We could start with something like this:

package com.jmg.insurance

class Product (insuranceAmount: Int, deductible: Int) {
  val rate = .05
  def premium = insuranceAmount * rate
}

object Main {
  def main(args: Array[String]): Unit = {
    val p1 = new Product(10000, 500)
    println(p1)
  }
}

The first line indicates that the class contained in this source file will be included in the package com.jmg.insurance

This is very similar to Java so far, but we will see that the Scala packaging system is more coherent and powerful than its Java counterpart.

Next, we see the definition of the class Product.

class Product (insuranceAmount: Int, deductible: Int)

Notice the parameters in parenthesis. These are the parameters of the primary constructor. Look further down, you will see the call to this constructor:

new Product(10000, 500)

Both parameters, the insurance amount and the deductible are declared of type integer. In Scala, like in Pascal or Eiffel we declare the identifier first, followed by a colon and the type, like:

insuranceAmount: Int

Java, in contrast follows the “C” tradition of putting the type first, followed by the identifier, like:

Integer insuranceAmount

It may be a little disturbing for you at first. Personally I was so used to the Java/C way that I forgot that years ago I felt the Eiffel/Pascal choice much more natural. Any way, this is a question of taste and habits. But there was a better reason for the Scala designers to adopt this syntax: the type inference. In Scala, you will see that we can skip the type declaration very often. Then it is easier for the compiler, when the optional part, the type, is at the end of the sentence.

Now a word about the type itself. In Java, you have two types for integers : int and Integer.

As you know, the former is the primitive type and the latter is a wrapper, allowing to see an integer as an object. There is no such duality in Scala. There is only one integer type Int. You can see it as an real object in all circumstances. You can call methods on it for example. The compiler is taking care of transforming this object in the platform’s primitive type when appropriate.

Now look again at the declaration of the class product:

class Product (insuranceAmount: Int, deductible: Int) {
...
}

I mentioned before that the parameters were the primary constructor’s ones. You may wonder where is the body of this constructor itself?

In fact, in Scala, the body of a class contains the methods, value declarations, plus the constructor’s body. In our example, this constructor is just empty !

It is closed to what is called a Java initialize block, like this:

package com.jmg.insurance;

class MyClass {
    private int someField;
    {
        [init block is here ...]
    }

Except that this Java initialize block is not really part of a constructor, so there is no way to use any constructor’s parameters.

So what happened to the parameters we are receiving when the constructor is called? Don’t we have to store them somewhere for later usage?

This is one of the magic thing that Scala does automatically for you. The constructor’s parameters are automatically available in all the methods of the class and are immutable.

So, this class declaration if roughly equivalent to this Java class.

package com.jmg.insurance;

class Product {

    private final Integer insuranceAmount;
    private final Integer deductible;
    private Double rate = .05;

    Integer getPremium() {
        return new Double(insuranceAmount * rate).intValue();
    }

    public Product(Integer insuranceAmount, Integer deductible) {
        this.insuranceAmount = insuranceAmount;
        this.deductible = deductible;
    }
}

This is equivalent to these lines of Scala code:

package com.jmg.insurance

class Product (insuranceAmount: Int, deductible: Int) {
  val rate = .05
  def premium = insuranceAmount * rate
 }

While it is true that conciseness is not everything, I think that Scala designers have captured here the essence of a very common use case: instantiating a class with a constructor and passing parameters to it. It relieves you from a lot of repetitive plumbing. And it is not finished!

In both the Scala and Java example above, you don’t have access, from outside of the class, to the values passed as parameters and now stored in this instance. For example, in some Java client code, this wouldn’t compile of course:

new Product(10000, 500).insuranceAmount

insuranceAmount is a private member, so to make it accessible to clients, we have to add an accessor method.

package com.jmg.insurance;

class Product {

    private final Integer insuranceAmount;
    private final Integer deductible;
    private Double rate = .05;

    public Integer getInsuranceAmount() {
        return insuranceAmount;
    }

    Integer getPremium() {
        return new Double(insuranceAmount * rate).intValue();
    }

    public Product(Integer insuranceAmount, Integer deductible) {
        this.insuranceAmount = insuranceAmount;
        this.deductible = deductible;
    }
}

Now clients can do this :

new Product(10000, 500).getInsuranceAmount();

To get the same thing in Scala, you just have to put the keyword val in front of the parameters for whom you want to have public access.

package com.jmg.insurance

class Product (val insuranceAmount: Int, val deductible: Int) {
  val rate = .05
  def premium = insuranceAmount * rate
 }

Now these parameters could be read, but not modified from client code. You could do, for example:

    val p1 = new Product(10000, 500)
    println(p1.insuranceAmount)

Don’t worry for now if you don’t understand yet a few details, like “how come we can write this?”:

println(p1) instead of: SomeObject.println(p1)

There is a lot of short-cuts like this one in Scala, but once you know the mechanics under the hood, it lights up and everything falls in place!

For now, the important thing is that you know what println means and does.

What if you want to be able, not only to read those parameters from client code, but also to modify them?

In Java, you will add another method, a mutator. Its name, by Java beans standards, would be setInsuranceAmount for example.

In Scala, just replace the keyword val in front of the mutable parameter by var

package com.jmg.insurance

class Product (var insuranceAmount: Int, var deductible: Int) {
  val rate = .05
  def premium = insuranceAmount * rate
}

Then you will be able to do the following in your client code:

    val p1 = new Product(10000, 500)
    p1.insuranceAmount = 15000
    println(p1.insuranceAmount)

Now let’s continue looking at our Product class declaration.

The second line: val rate = .05 defines a value (as indicated by the keyword val) and assigns to it the value “.05” which is a floating point value.

We could have written: val rate: Double = .05, but the type inference system seeing the constant “.05” is able to assign automatically the type Double to the identifier rate

The next line: def premium = insuranceAmount * rate is a method declaration. When invoked, this method will return a result of type Double. This result is computed as the product of rate by insuranceAmount

The full and somewhat redundant declaration would be
def premium: Double = insuranceAmount * rate
but again the smart type inference system can deduct from the calculation formula that the result must be of type Double.

In the next article, we will continue to show more and more features of the Scala language as they become necessary to enrich our small example.

“Perfection interne et confirmation externe”. Tels étaient les deux critères, selon Einstein, pour juger de la valeur d’une théorie scientifique.

Le degré de perfection interne d’une théorie est d’autant plus élevée, que le nombre d’axiomes de base sur lesquels elle est fondée est plus restreint.

Perfection interne est donc en quelque sorte synonyme d’élégance.

Quant à la confirmation externe, il s’agit bien entendu de la concordance entre les phénomènes observés et les prévisions de la théorie.

Au fond, puisque que le mérite ultime d’une théorie, c’est de représenter le plus possible la réalité, alors admettre le premier des deux critères précédents revient à postuler que la “réalité” ou la “nature” doit aussi posséder cette même perfection interne, ou élégance.

Bien entendu, ceci suppose que l’on adhère au système de pensée selon lequel il existe une réalité objective, connaissable et indépendante de nous, que nous tentons de découvrir à travers le miroir déformant de nos perceptions et dans les limites des capacités de notre cerveau.

Einstein croyait à cette réalité objective et “a priori”.

Quel rapport avec l’informatique? J’y viens, ayez un peu de patience!

Grady Booch disait aussi dans un de ces livres, en substance : « Si vous voulez concevoir des systèmes complexes qui aient quelque chance de succès et qui supportent l’épreuve du temps, alors étudiez des systèmes qui ont fait leurs preuves et fonctionnent bien. La nature en montre de nombreux exemples».

Une plante, un animal, par exemple sont des systèmes effroyablement complexes et cependant très robustes et résilients.

Leur complexité n’est pas arbitraire, on peut l’appréhender en décomposant ces systèmes à des niveaux d’abstractions grossiers, puis de plus en plus fins.

Mes connaissances en botanique sont très sommaires mais je crois qu’on peut dire schématiquement qu’une plante se compose d’un sous système racinaire et d’un sous système “feuillage”, chacun ayant son role. Les racines absorbent l’eau du sol et certains nutriments. Le feuillage a pour fonction la photosynthèse et la reproduction etc.

Donc on voit que même un système complexe, peut être compris à un niveau grossier d’abstraction. Bien entendu, des connaissances de plus en plus spécialisées sont nécessaires pour appréhender les niveaux plus fins d’abstraction.

Ainsi que le soulignait Grady Booch, la complexité des systèmes naturels repose sur deux “patterns” essentiels : la composition et la spécialisation.

La composition est le fait que ces systèmes sont batis comme des assemblages de sous systèmes, qui sont à leur tour décomposables en parties de plus en plus fines.

Quant à la spécialisation, en poursuivant avec la métaphore botanique, on pourrait dire que la plante est ultimement composée de cellules, dont il existe différents types spécialisés.

Ces deux patterns se retrouvent en design de systèmes sous les termes de “composition” et “polymorphisme”.

Pourquoi les systèmes naturels seraient ils toujours élégants?

En fait ceux qu’il nous est donné d’observer, c’est à dire ceux qui ont survécus, le sont !

L’élégance est également apparentée avec la notion d’économie de moyen. La nature semble toujours tendre vers ce but.

N’en déplaise aux créationnistes, tous ces systèmes que nous observons ont été batis par des processus évolutifs.

Si nous voulons bâtir des systèmes complexes, il faut avoir la modestie de reconnaître qu’il est difficile voir impossible d’en concevoir un du premier coup, “ad-nihilo”.

Les meilleurs systèmes sont donc bâtis par un processus itératif et incrémental.

Toutefois, ces évolutions successives devraient idéalement ne jamais laisser de traces apparentes des “errements” par lesquels le designer sera passé. “Les raisons historiques” voilà l’ennemi !

Une bonne façon de savoir si vous avez échappé à cette embuche, c’est de tenter d’expliquer le système que vous avez conçu à une tierce personne extérieure au projet. Si vos couches d’abstraction sont bien pensées, vous n’aurez pas de difficulté à faire comprendre le système en progressant depuis les abstractions les plus générales, jusqu’aux détails les plus fins. À chaque niveau, votre interlocuteur pourra vous suivre, car les détails non encore dévoilés, des niveaux inférieurs, ne nuiront jamais à sa compréhension du niveau courant.

Je trouve personnellement cet exercice agréable et valorisant. Il vous confirme que vous êtes sur la bonne voie. Quelque fois, les remarques et les froncements de sourcil de votre interlocuteur vous amèneront à certaines remises en question. N’hésitez pas à les faire.

En revanche, si vous êtes obligés d’invoquer des “raisons historiques” pour justifier certaines parties de l’architecture, l’exercice devient alors inutile et frustrant. L’autre personne ne peut plus vous “challenger”, l’argument est sans appel. Puisqu’elle n’était pas présente lors de ces phases “historiques”, que pourrait-elle en dire?

Si vous n’avez pas la possibilité de faire ce transfert de connaissance, alors pourquoi ne pas essayer de documenter le système?
C’est un exercice semblable. Pourquoi de nombreux informaticiens n’aiment pas documenter? Ne serait-ce pas justement à cause de la difficulté d’expliquer clairement un design composée de strates, laissant apparaître nos errements successifs, et n’ayant pas subi les indispensables retours arrière et “refactoring”?

En conclusion:

La nature est efficace, élégante et sa complexité est “décomposable”. Comme le dit Hubert Reeves, la nature est “structurée comme un langage”, formé de lettres, puis de mots, puis de phrases, chapitres, livres… Nos systèmes devraient suivre cet exemple.
Deuxièmement, la nature a été bâtie par un processus évolutif. Faisons de même.

La sagesse populaire dit que “la critique est aisée mais l’art est difficile”. Critiquons donc sans relâche notre design à chaque itération et améliorons le !

J’avais pensé écrire ce blog en anglais…

À la réflexion toutefois, je préfère utiliser la langue que je manie le mieux. Et je ne veux pas me priver du plaisir réel que j’éprouve à écrire en français.

Sans doute utiliserai-je l’anglais pour certains textes techniques.

“The computer is naked !”

Vous l’aurez peut-être deviné, est une référence au conte de Hans Christian Andersen : “Les habits neufs de l’empereur”.

Ce conte illustre un comportement enraciné dans l’âme humaine et par conséquent de toutes les époques.

«Si l’on constate un consensus quasi général sur un sujet donné, parmi des individus qui semblent bien informés, on aura tendance à faire taire son jugement, même si notre propre analyse nous fait douter de cette “évidence”»

La motivation de cette attitude est souvent la crainte de passer pour incompétent en n’adhérant pas à la pensée commune, la crainte de voir ce petit sourire ironique ou apitoyé qu’on ne manquera pas de vous adresser.