I guess I missed the point in my (rather terse) example.
What I was demonstrating is that the expression doesn't just change the
contents of the collection, but also the type of the collection itself.
For example:
*val bitSet = BitSet(1,2,3) //a BitSet can only hold integers, it
subclasses Set[Int]*
*val res1 = bitSet map {2*} //BitSet(2,4,6)*
*val res2 = bitSet map {_.toString} //Set("1","2","3") BitSets can't hold
strings, so returns a Set[String], as per the Liskov Substitution
Principle. *
*
*
*val myMap = Map(1 -> "x", 2 -> "y", 3 -> "z") //a Map[K,V] is also a
collection of K->V pairs*
*val res3 = myMap map {x => x._1.toString -> x._2}
//Map("1"->"x","2"->"y","3"->"z"),
a Map[String, String]*
*val res4 = myMap map {case (a,b) => a.toString -> b} //more readable via
pattern matching*
*val res5 = myMap map {_._1} //List(1,2,3), a List[Int]*
*val res6 = myMap map {_._2} //List("x","y","z"), a List[String]*
This is all 100% safe and statically typed, and is made possible by the
"scary" CanBuildFrom implicit parameter that Stephen mention in his article.
I don't believe that Fantom can do this, not least because it doesn't have
highly-optimised collection types such as BitSet, it doesn't consider Maps
to subclass collections of pairs, and it doesn't support creation of your
own paramaterised collection types. So far as I'm aware, Scala is the only
language in existence that directly supports such a scheme (though I
imagine it would be totally possible to duplicate using something like Lisp
macros)
It looks threatening in the documentation, but when you actually use this
stuff it's really quite effortless. The best part is that these
collections are defined entirely in library code using completely standard
syntax without a single line of compiler support required. Anybody could
have implemented them without touching the compiler, and it's completely
possible to implement your own collection types that fit transparently into
this hierarchy (although you *do* have to understand the full method
signatures at that point)
2011/11/24 Cédric Beust ♔ <[email protected]>
> On Wed, Nov 23, 2011 at 3:05 PM, Kevin Wright <[email protected]>wrote:
>
>>
>> They're also core to the mechanism that allows collections to just do the
>> Right Thing(tm). For example:
>>
>> someBitSet map {_.toString}
>>
>
> Right, but you can achieve the same result without needing implicits. I'll
> just show how Fantom does it but I'm sure the same applies to
> Gosu/Ceylon/Kotlin:
>
> // a set of A instances, where A has a toUppercase method
> aSet := [ A("foo"), A("bar") ]
> l := aSet.map | v->Str | { v.toUppercase }
> echo(l)
> echo(l.typeof)
>
> [FOO, BAR]
> sys::Str[]
>
> The signature of map() is exactly what you would expect: it takes a
> function that takes an element of the collection and returns "something",
> and the type of your expression is "list of something" (here we transformed
> a list of A's into a list of strings).
>
> It's really not rocket science, and the fact that you need implicits to
> achieve this result is an implementation detail that's very specific to
> Scala.
>
> Sure, you can handwave it with "You don't need to understand the exact
> details of the API", but the truth is... you really do. Not a week goes by
> without me having to go check out a Javadoc or the signature of java.util
> or Guava method. And saying that only library authors need to know about
> implicits, CanBuildFrom and its triple generic signature is creating a rift
> between the Scala developers (people who know and people who don't), which
> is worrisome.
>
>
--
You received this message because you are subscribed to the Google Groups "The
Java Posse" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/javaposse?hl=en.