True Scala complexity
21–30 of 152 posts
Re: True Scala complexity
#22After reading a bunch of these articles and really walking away unimpressed this one is fantastic. It does a great job of showing how cryptic you can make Scala code. It also shows that the same topic on which half the article is spent explaining can be boiled down to four lines of less "Scala Like" code. As a pragmatic user of Scala I don't see why the fact that you _can_ do some amazing but cryptic things with the…
Because you hit the cryptic too soon, and you can't really avoid it. And I generalize this to any such language that has this characteristic, not just Scala. You can't use C++ for very long without having to know huge swathes of it if you want to use the libraries created by others, and you want to be able to debug why they don't work perfectly. (Bearing in mind "working perfectly" also includes you having a correct mental model of how they work, which is tricky if you only have a subset of the language in your head!) Same for Haskell. Compare with Python, where you basically can learn a reduced subset of the language, yet still use libraries fairly effectively. You need to know the basics of having objects and calling methods. You don't need to know how to write your own iterator, any of the double-underscore methods or the resulting protocols, you probably don't need to know decorators (and even if you do, probably just how to use them, because they are unlikely to bite you in odd ways if you just copy-paste instances of them), you don't need to know metaclasses, etc.
Type systems of almost any kind are very hard to satisfy without understanding. In some sense, this is one of the very constraints the stronger ones are trying to enforce.
Re: True Scala complexity
#23Fantastic post. The most salient excerpt for me: def filterMap[B,D](f: A => Option[B])(implicit b: CanBuildFrom[?,B,D]): D def filterMap[B,D Option[B])(implicit b: CanBuildFrom[?,B,D]): D def filterMap[B,D Option[B])(implicit b: CanBuildFrom[?,B,D]): D def filterMap[B,D[B]](f: A => Option[B])(implicit b: CanBuildFrom[?,B,D[B]]): D[B] def filterMap[B,D[B] Option[B])(implicit b: CanBuildFrom[?,B,D[B]]): D[B] def filter…
In practice, I almost never use monkey-patching in dynamic languages because it's too dangerous. While in Scala there are cases where enrichment won't work, you can always just write a regular function in those cases, and there are lots of cases where enrichment _does_ work...
Re: True Scala complexity
#24Re: True Scala complexity
#25Fantastic post. The most salient excerpt for me: def filterMap[B,D](f: A => Option[B])(implicit b: CanBuildFrom[?,B,D]): D def filterMap[B,D Option[B])(implicit b: CanBuildFrom[?,B,D]): D def filterMap[B,D Option[B])(implicit b: CanBuildFrom[?,B,D]): D def filterMap[B,D[B]](f: A => Option[B])(implicit b: CanBuildFrom[?,B,D[B]]): D[B] def filterMap[B,D[B] Option[B])(implicit b: CanBuildFrom[?,B,D[B]]): D[B] def filter…
public static class EnumerableExtensions
{
public static IEnumerable FilterMap(this IEnumerable list, Func> callback)
{
...
}
}
There are some methods that need to be part of the class and carried around with the instance so that things like polymorphism work. But many operations work perfectly fine without. By making those lexically scoped, you avoid the problems of monkey-patching and method collisions. Extension methods are fantastic for this.Also, for kicks, Magpie:
def (items) filterMap(callback)
var result = []
for item in items do
match callback(item)
case true, mapped then items add(mapped)
else nothing
end
end
result
end
var result = [1, 2, 3, 4, 5, 6] filterMap with
if it % 2 == 0 then (true, it * 2)
end
print(result) // 4, 8, 12
Magpie is dynamically-typed, but methods are lexically-scoped (and are multimethods).Re: True Scala complexity
#26I wonder how much of an impact it would be if Scala simply had better documentation . I love the terseness of the code and the complex things you can do, but I'll be damned if I could ever glean ideas from looking at method definitions rather than code examples.
There's also a new docs site and it's getting better all the time: http://docs.scala-lang.org/
Re: True Scala complexity
#27Fantastic post. The most salient excerpt for me: def filterMap[B,D](f: A => Option[B])(implicit b: CanBuildFrom[?,B,D]): D def filterMap[B,D Option[B])(implicit b: CanBuildFrom[?,B,D]): D def filterMap[B,D Option[B])(implicit b: CanBuildFrom[?,B,D]): D def filterMap[B,D[B]](f: A => Option[B])(implicit b: CanBuildFrom[?,B,D[B]]): D[B] def filterMap[B,D[B] Option[B])(implicit b: CanBuildFrom[?,B,D[B]]): D[B] def filter…
The existing collections functions in Scala take you very, very far. If you need to write your own primitives for performance reasons, it can get tricky, but that's really uncommon. Odersky's book (chapter 25) explains how to do that.
Collections libraries are hard in Scala because of what you get. Once you define a few simple functions and possibly implicit conversions, you get all 50+ sequence methods "for free", and if you do it right, your map type functions will return collections of the same type (runtime and static) as the original-- without explicit typing. You get a lot of leverage, but you have to work a little bit for it.
Re: True Scala complexity
#28A lot of the items the post author describes as complex you can't do at all in other languages. "Simple things should be simple, complex things should be possible." - Alan Kay I don't think the blog author gives particularly great examples of simple things that are made complex by the language. He simply gives examples of things that are inherently complex that scala at least makes possible.
I have to respectfully disagree. First of all, the things he shows aren't inherently complex: adding an additional function to the existing collections library is something that's possible in other languages in less confusing ways (see other examples in this post). The various concepts required to solve the problem in Scala like implicits and higher kinds might be inherently complex, but the problem he's trying to so…
It's very easy to write a new function for your particular case. You can write an acceptable map function for your new collection, or a new list-munching function, just as easily as in ML. It will be a top-level function instead of a method, but that's usually just fine (if inelegant).
The long-term risk you are taking is that you might want this list-munching function to apply to other collection types and will now have code duplication.
What Scala offers is the ability to write new methods that apply to all collections (Strings, BitSets, Lists) if you wish... and to create new collections types (with a little bit of work and comprehension, but not as much work as is involved in writing 50+ library functions by hand) that automagically end up with all the collections functions.
This impressive and quite radical code reuse is the part that's hard about Scala, but that's only relevant if you want to write libraries at the L2/L3 level of quality and beauty.
Re: True Scala complexity
#29Re: True Scala complexity
#30eg. The following fails:
Set(1,2,3).toIndexedSeq sortBy (-_)
But doing the same in 2 steps, ie. after assignment, works
val xs = Set(1,2,3).toIndexedSeq; xs sortBy (-_)
I have been bitten by this several times now, so I don't unnecessarily chain > 2 functions even if it does compile ( which also solves one other brainteaser posed in that article ) Have also seen the problem with the add function, when I wrote a matrix manipulation library.
def add(x: Int, y: Int) = x + y
add(1,_) fails, but add(_,_) works. Even though the error message " missing parameter type for expanded function" seems reasonable, and providing the parameter type ie. add(1,_:Int), does compile, the bahavior is hard to explain to newbies.
His point about hanging your hat on asInstanceOf[...] and the resulting code being clumsy...ok, guilty as charged, but then you only have so many hours in a day, and mgmt is paying $$ to solve boring business problems ( compute the asset quality of five million loans in thirty lines of business over twelve quarters using scala ) and not mucking around ( add a filterMap to the scala collection library to get an idiomatic Scala implementation )
I enjoyed the programming snippets in the article very much, but I still don't get what the point of the rant was. He goes on and on about "lack of acknowledgement of complexity", but what does that really mean ? Does he want like a gold star ? Even if everybody acknowledges that scala is complex, what then ? Eventually some of it will get fixed & the rest will not & life will go on. Why be a downer at such an early phase of growth of the language ? All this talk of excess complexity will simply scare off the early adopters. Java has been around for 15 years and we still don't have decent generics. Scala is so far ahead in such a short time. Patience, etc.