Skip to content


Scala vs Java

Ich habe mir gestern ein Scala-Codebeispiel angesehen, dass Scala-Objekte von und nach JSON konvertieren kann. Ich muss zugeben, dass es ein wenig gedauert hat, bis ich den Code verstanden habe. Das liegt unter anderem daran, dass ich in Scala einfach noch nicht gut genug bin. Der andere wichtigere Punkt ist aber folgender:

Wenn man bisher mit einer Reihe von Java-Klassen ein Framework für eine bestimmte Aufgabe entwickelt hat, kann man die selbe Anforderung mit einigen wenigen Scala-Klassen abbilden.

Das bedeutet, dass sich die Funktionalität mit sehr viel weniger Code darstellen lässt. Das spiegelt die Befürchtung wieder, dass man mit Scala Code schreiben kann, der schwer zu vestehen ist. Doch dieser erste Anschein trügt. Der Code ist nur um vielfaches dichter und deshalb natürlich schwerer zu verstehen als ähnlich umfangreicher Java-Code. Der funktionsäquivalente Java-Code wäre aber entsprechend umfangreicher und kann im Zweifel schon deshalb nicht ansatzweise so gut überblickt werden. Ich kann es daher nicht nachvollziehen, dass dieser Punkt gegen Scala sprechen soll.

Ich glaube, dass die Entwicklung bei Scala insofern noch am Anfang steht, als dass das Ausloten der Sprachemöglichkeiten und die kreativen Auslegungen der Plattform noch in den Kinderschuhen steckt, gerade wenn man betrachtet, wo wir uns da im Java-Umfeld befinden. Doch diese Kinderschuhe sind bereits jetzt viel größer und der kleine Bub schaut entspannt über die Köpfe seiner Eltern hinweg.

Tags:

Veröffentlicht in Allgemein, scala, Technologie, .

Wicket und Scala - der Rückweg ist anstrengend

Ich habe mal ein wenig mit Scala rumgespielt und mit den Sprachmöglichkeiten, die Scala bietet, versucht aus einem Java-lastigen Wicket-Beispiel etwas zu machen, was sich wie Scala anfühlt. Zuerst der Java-Code:

package de.flapdoodle.incubator.scalawicket.web.pages;

import org.apache.wicket.Component;
import org.apache.wicket.IClusterable;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxFallbackLink;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;

public class StartJava extends WebPage
{
  public StartJava()
  {
    IModel messageModel=Model.of("Huiii");
    final Label label=new Label("message",messageModel);
    label.setOutputMarkupId(true);
    
    add(label);
  
    final Bean bean=new Bean();
    bean.setName("Klaus");
    bean.setAlter(12);
   
    final Component labelName = new Label("name",new PropertyModel(bean,"name")).setOutputMarkupId(true);
    final Component labelAlter = new Label("alter",new PropertyModel(bean,"name")).setOutputMarkupId(true);
    add(labelName);
    add(labelAlter);
    
    final Form form=new Form("form", new CompoundPropertyModel(bean));
    form.add(new TextField("name")).add(new TextField("alter"));
    form.setOutputMarkupId(true);
    add(form);
    
    add(new AjaxFallbackLink("link",messageModel)
    {
      public void onClick(AjaxRequestTarget target) 
      {
        getModel().setObject("Klick");
        bean.setName("Peter");
        target.addComponent(form);
        target.addComponent(label);
        target.addComponent(labelName);
        target.addComponent(labelAlter);
      }
    });
  
    add(new AjaxLink("link2",messageModel)
    {
      @Override
      public void onClick(AjaxRequestTarget target)
      {
        getModel().setObject("Klack");
        bean.setAlter(24);
        target.addComponent(form);
        target.addComponent(label);
        target.addComponent(labelName);
        target.addComponent(labelAlter);
      }
    });
  }
  
  class Bean implements IClusterable
  {
    String _name;
    int _alter;
    public String getName()
    {
      return _name;
    }
    public void setName(String name)
    {
      _name = name;
    }
    public int getAlter()
    {
      return _alter;
    }
    public void setAlter(int alter)
    {
      _alter = alter;
    }
  }
}

.. und nun das ganze in Scala

package de.flapdoodle.incubator.scalawicket.web.pages;

import org.apache.wicket.Component;
import org.apache.wicket.IClusterable;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxFallbackLink;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import de.flapdoodle.incubator.scalawicket.web.wicket.WicketHelper._
import scala.reflect.BeanProperty;

class Start extends WebPage 
{
  val messageModel=Model.of("Huiii")
  val label=new Label("message",messageModel)
  label.enableAjax
  
  this+=label;

  val bean=new Bean
  bean.name="Klaus";
  bean.alter=12;

  val labelName = new Label("name",bean model {_.name}).enableAjax
  val labelAlter = new Label("alter",bean model {_.alter}).enableAjax
  this+=labelName
  this+=labelAlter
  
  val form=new Form[Bean]("form", new CompoundPropertyModel[Bean](bean));
  form+=(new TextField("name"),new TextField("alter"))
  form.enableAjax
  this+=form
  
  this+=new AjaxFallbackLink[String]("link",messageModel)
  {
    override def onClick(target: AjaxRequestTarget) = 
    {
      this.model set "Klick"
      bean.name="Peter"
      target.refresh(form,label,labelName,labelAlter)
    }
  };

  this+=new AjaxLink("link2",messageModel)
  {
    override def onClick(target: AjaxRequestTarget) =
    {
      this.model set "Klack"
      bean.alter=24
      target.refresh(form,label,labelName,labelAlter)
    }
  };

  class Bean extends IClusterable
  {
    @BeanProperty
    var name: String = _;
    @BeanProperty
    var alter: Integer = _;
  }
}

Zuerst zu den offensichtlichen Dingen:

  • Java: Zeilen=91, Wörter=155, Zeichen=2.567
  • Scala: Zeilen=69(75%), Wörter=126(81%), Zeichen=1.921(75%)

In diesem Beispiel kann Scala seine Vorteile vielleicht noch nicht richtig ausspielen. Wobei 25% weniger Schreibarbeit (wenn man vernachlässigt, dass ich einmalig etwas Scala-Code schreiben musste, was mir das ermöglicht) für dieses Beispiel vielleicht auch schon eine bemerkenswerte Menge ist.

Spannender ist folgender Umstand: Ich habe den Java-Code aus dem Scala-Code abgeleitet. Wenn ich das Beispiel direkt in Java geschrieben hätte, sähe der Code fast genauso aus. Als ich aber den Scala-Code rückübersetzte, fiel es mir sehr schwer, die ganzen Typ-Definitionen zu schreiben, die abschließende Semikolons zu setzen und Parameter in geschweifte Klammern einzubetten. Auch wenn die Unterstützung für Scala in Eclipse noch einiges Potential hat, kann man a) damit bereits erstaunlich gut arbeiten (wenn man bedenkt, welche interessanten Sprachmöglichkeiten (und damit Schwierigkeiten für eine IDE) Scala bietet).

Meine schönste Zeile Code ist in diesem Beispiel das Erzeugen eines AbstractReadOnlyModel durch den Aufruf von "bean model { _.alter }" , der in diesem Fall das selbe leistet wie ein PropertyModel, nur dass das Attribut nicht erst per Reflection ermittelt wird.

Ich warte eigentlich darauf, dass jemand Wicket nach Scala portiert, denn das Lift-Framework gefällt mir nicht so gut (da wird wieder Code in die Templates verlagert). Jetzt geht es erst einmal weiter mit Java, auch wenn der Rückweg jetzt schon ein beschwerlicher war.

Tags:

Veröffentlicht in Allgemein, Refactoring, scala, Wicket, .