Skip to content

Instantly share code, notes, and snippets.

@razie
Created September 24, 2010 15:35
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save razie/595556 to your computer and use it in GitHub Desktop.
Save razie/595556 to your computer and use it in GitHub Desktop.
Scala abuses

Scala is a wonderful language, with a specification of a size comparable with that of Java. Overall, the specification is simpler than C++. Why then do a lot of people feel intimidated by the expresiveness of scala?

Scala can generate complex constructs. There are some features of the language that, if not used properly, can negatively influence one's perception of the simplicity of the language and generate a waste of many an hour of a frustrated developer.

I find this to be especially true of Java developers just picking up scala. Since they do not have a full grasp of all the features of the language and their effects or benefits, they may be very surprised if others on their team use them.

One thing to have when starting or using scala is a readily available bible. I recommend "Programming in Scala", the .pdf version, an easily searcheable language reference.

The scala style guide www.codecommit.com/scala-style-guide.pdf is a must. Here we will describe the advanced features of the language that should not be abused or better, avoided by the regular Joe.

Language constructs that regular Joe should NOT ABUSE

Do not abuse:

  • many constructors for the same thing. These come in many kinds, from this() to apply() in a companion class to implicits
  • anonymous functions everywhere
  • the def f()()()() notation - it's ok only to allow DSL looking constructs
  • avoid variance notation
  • _ (underscorre)
  • do not chain many function calls in the same line.
  • operators
  • implicits visible outside of a class
  • complext type restrictions
  • variance notation
  • complex higher types

Dont (re)define operators

Do not re-define operators or define new ones. For instance:

// this is mean and considered sabotage - good reason for firing developers
override def + (that:String) = this - that

// coming up with operators 'cause you feel like not doing your job on a friday
def --++==--++ = 5

Implicits visible outside of a class

You could use implicits inside a class or object, to simplify the code and learn it. DO NOT make them visible outside the class

Do not abuse _

The wildchar is used in many circumstances:

  • currying: f _
  • ignore types: List[_]
  • ignore values in pattern matching: case Student (_,a) => ...
  • match anything: case _ => ...
  • stand-in for parameters in lambda sugar-coated syntax: list map (_ + 2)

Complex type restrictions

When defining higher order types, stay away from complex type restrictions.

// this is typical
val students : List [A <% Student]

// this is ok - although you should use Option rather than null
class NoStatic[T>:Null<:AnyRef] {
   var lazyValue = null
}

//this is to be completely avoided
def combo[AA <: A >: B <% String <% Int : M : Ordering] = 0

Do not chain many function calls in the same line.

No more than 2 map()s in the same line. Note that getOrElse is a type of map for this purpose.

//This is borderline comprehensible:
SystemProps.sPatProps.find (_.patcomp.pattern.matcher(name).matches) map (_.value) getOrElse System.getProperty(name)

// not so here - actually here an inline lambda is abused
o._2.asInstanceOf[List[scala.xml.Elem]].filter(zz => XP.stareq(zz.label, tag)).map(x => { val t = (x.asInstanceOf[T], children(x).toList.asInstanceOf[U]); println("t=" + t); t }).toList

//here the name is very useful and excuses the rest of the line
def messagesById(id: String)(f: => List[(NodeSeq, Box[String])]): List[NodeSeq] = f filter (_._2 map (_ equals id) openOr false) map (_._1)

//not here, though
val ret = (Box(connectionManagers.get(name)).flatMap(cm => cm.newSuperConnection(name) or cm.newConnection(name).map(c => new SuperConnection(c, () => cm.releaseConnection(c))))) openOr { ... }

Complex higher types

Generally, higher-order types are already provided for you, in the collection libraries. If you need your own Group[Student], then you should keep it simple.

The example may look comprehensible, but using it may cost a lot of time...

trait WRGraph[N <: GNode[N, L], L <: GLink[N]] extends GNode[N, L] { this: N =>
...
}

The def f()()()() notation - it's ok only to allow DSL looking constructs

//this is customary
def using (r:Resource) (f: Resource => Unit) = ...

// this is pointless
def add (i:Int) (j:Int) = i + j
// unless you need to curry it:
add (3) _
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment