|
Re: Implicit Arguments in Scala
|
Posted: Mar 8, 2008 10:54 AM
|
|
Scala is supposed to tackled larger projects than languages like Java.
However, I have seen disturbing trends in the Scala blogosphere, where almost all Scala bloggers seem to be obsessed with outdoing Ruby and Perl in writing one-liners that only less than 1% of the programming community is capable of understanding (granted, they are the smartest 1%, but think about the 99% who have to waste time trying to understand it when, with very little extra implicit code everyone could benefit).
Features like the Perlish _ (think $_) and implicit arguments will allow clever code, but at what cost?
I learned and used Perl in the "post Best Practices" world (not the book, which came later), and I saw first hand, in the field, where those best practices were applied---a huge chunk of it was about discouraging the (ab)use of most things implicit.
I am perfectly ok with features that reduce obfuscation through boilerplate (e.g., like the ones that we have to deal with in languages like Java, C, etc) However, obfuscation can, and in more cases, go the other way. The question is: What do we gain? A few keystrokes (10-20s saved) while writing vs. 10-20 minutes of trying to figure out what is going on (which have to be repeated with each new programming who will have to use this)
It is unclear from the article what exactly we would gain from this.
The ability to declare an input that matches a latent type for a single method? What if I have two methods with such methods. All we have to rely on is type info.
The following tries to build a situation where this implicit feature comes in handy (based on the examples in the article):
object Ri { def f(x: String)(implicit y: String) = "R.f(" + x + "," + y + ")" }
object Mi { def g(x: String, y: String)(implicit z: String) = "M.f(" + x + "," + y + "," + z + ")" }
object Pain extends Application { implicit val x = "A" // implicit val y = "L" // not possible (to avoid ambiguitiy) println( Ri.f("Va") ) println( Ri.f("La") ) println( Mi.g("Yo", "Yo") ) println( Mi.g("Da", "Ja") ) }
Now, that is handy to call Ri.f(). But now I can't give a different value for Mi.g() (which is better than having random behavior). But worse, no warnings will be issued if I missed (in this case, it is quite unlikely, but quite likely in real life). What if this is part of a library that you did not write. Accidents can happen.
The same thing can be done much more safely, and with greater flexibility, using partial functions, currying (or whatever it is called) (and in this case, a lot less boilerplate, 8 characters less :-) ).
object R { def f(y: String)(x: String) = "R.f(" + x + "," + y + ")" }
object M { def g(z: String)(x: String, y: String) = "M.f(" + x + "," + y + "," + z + ")" }
object Main extends Application { def fx = R.f("A")_ def gx = M.g("L")_ println( fx("Va") ) println( fx("La") ) println( gx("Yo", "Yo") ) println( gx("Da", "Ja") ) }
I suppose I haven't understood this very well. Probably have to go through David MacIver's suggested readings to find more examples.
Although, I am sceptical about the cost-benefit advantage of implicit arguments, I thank bloggers like David R. MacIver and Daniel Spiewak for regularly providing insights into Scala and other things. Keep blogging.
|
|