Hacker News new | ask | show | jobs
by Artemidoros 5877 days ago
Using implicits is really nice to clean up the interface to some Java APIs (especially for APIs making heavy usage of anonymous inner objects) but I experienced more ugly boilerplate than I would like when having to use Java collection classes from Scala, too.

To be more specific, when I want to transform a collection given by a Java library in a functional manner, I usually ended up with one or two localized import statements - to avoid e.g. scala.collection.mutable leaking into my other methods - and additional calls to convert the Java collection into a Scala specific and back again. This doesn't look like a big issue, but it increased the line count for a lot of cases from '1' to 3-5 ... which puts it uncomfortably close to 'dumb for loop territory'.

Admittedly, this is a small price to pay compared to the constant annoyance that is Java, but for my part I fear that there might be a slight tendency in Scala to fix interesting problems preferably to useful ones.

... lost any type information within the scala language at compile or link time...

How about this use case?

match { case x: List[Foo] => ... case x: List[Bar] => ... }

give me Scala any day of the week

Why do you have the preference for Scala? I'm curious because Scala is my language of choice for my personal projects, but I would ditch it the second a credible F# derivative would appear on the JVM (F#'s stronger emphasis on functional programming, cleaner syntax and abstaining from 'fixing typing' in OOP are the reasons for my preferences).

2 comments

Out of curiosity, what do you mean by "fixing typing"? (I'm genuinely curious. I don't know Scala and F# well enough to really understand.)
My guess as to what the poster was about (warning: sleep deprived today, rambling ahead):

F# has basically two type systems -- the O'Caml/ML one, and C#'s. As a plus, you get full type inference so long as you stick with ML discriminated unions or records; as a minus, you lose the ability to apply concepts from OO without converting them to classes -- in which case you lose the ability to apply some handy ML-isms.

Scala tries to pull off a fairly deep unification of OO with functional types; for example making discriminated unions into case classes; or blending OO ideas of objects and classes with ML ideas about modules (including functors) into a single concept. It's far more ambitious in this regard than F#, but not necessarily an unqualified success either.

yes thats about what I meant, and more concise than my own explanation :-)
e.g. is SomeCollection<String> a subtype of SomeCollection<Object> (using Java like Syntax)? For some type of collections in some kind of circumstance this might be sensible (e.g. when your collections are immutable), sometimes having an inverse relationship might be appropriate and in some case you don't want these two types to be related at all (like Java collections - Arrays being the exceptions).

Co/Contravariance (maybe View Bounds?) in Scala enable you to encode this relationship, but from my understanding are somewhat handicapped by type erasure.

Another problem Scala tackles is that using inheritance as a 'code sharing facility' is a bit tricky (e.g. tractability and fragile base class problem) and not composable. Scala's traits and Self Types are a real improvement in this regard. That the order of mixing in traits can have an influence the objects behavior while not its type can be seen as a problem though.

F# takes the .Net object system 'as is' and introduces 'types' more aligned to functional programming (aka. discriminated unions) as separate entities. It does not try to integrate both concepts as does Scala with its case classes.

> To be more specific, when I want to transform a collection given by a Java library in a functional manner, I usually ended up with one or two localized import statements - to avoid e.g. scala.collection.mutable leaking into my other methods - and additional calls to convert the Java collection into a Scala specific and back again.

I think the other poster was right about this being more of a library issue than a language issue. In my experience it was rare to do more than wrap Java collections to or from an Iterable[]; that could be done easily without having to bring full mutable collections into the namespace.

Also, it might be part of the cost of working with "enterprise" Java, but it was actually really rare for me to work with a vanilla Java collection rather than some library's implementation of its own damn 'typesafe' iterator, like this: http://xerces.apache.org/xerces-j/apiDocs/org/w3c/dom/NodeLi.... It was super-nice to toss together my own wrappers of some library or another's semi-standard iteration API and have a ton of functionality come along via the magic of mixins; and get it all automatically applied for the cost of a single import statement via implicits.

> match { case x: List[Foo] => ... case x: List[Bar] => ... }

I suppose such a thing is made impossible via erasure, it's true. I haven't encountered a need for it -- maybe because the problem there is erasure + dynamic/runtime typing, rather than erasure on its own. Also it's something that's coming for Scala, it sounds like. (I haven't paid as much attention as I should to its ongoing development..)

> Why do you have the preference for Scala?

Part of it's just the intuitive feel: When I code in Scala, I'm writing in Scala -- it might be a fairly huge language, but it is its own thing. Coding in F# feels like bouncing back and forth between C# and O'Caml, depending on how functional you're feeling at the moment -- here's a C#-ish clause; there's an O'caml-esque one.

As an example, I don't believe you can use both inheritance and discriminated unions in F#. In Scala you can and it's actually quite useful.

Another example is that in F# you can omit type declarations on function arguments until you start using OO, then they become mandatory and infect your code. On the one hand the extra inference is nice but on the other it really drives home that you are coding in two languages, not one.

Besides that intuitive part, I think that Scala's module/class-level type system, although complicated, helps tremendously for writing big, complex, programs. Traits/mixins, flexibility in type constraints, and allowing types as members of other types add up to a really powerful ability to modularize without sacrificing. At least for me, a lot of my older O'Caml projects made fairly heavy use of functors. F# didn't bother to try to support the idea and only supports plain-vanilla C# interfaces. Scala embraced them, extended it, and made them much better.

In my experience it was rare to do more than wrap Java collections to or from an Iterable[]

Could you give me a simple example how say filtering and mapping a collection received by a java library and pushing it back to a method expecting a collection of the original type would look like? (quite likely that I overcomplicate this in my own code)

Sorry for the late reply.

Assuming you want your maps and filters to be purely functional, you need only two simple methods: One that constructs an object that implements the Iterable[X] trait from the java object, and another that constructs an instance of the java collection from an Iterable[X]. All the implementation that you'd like is already done for you in the iterable trait, but you can always selectively override them if you'd like to provide a more tailored implementation.

Then it's up to your taste whether you'd like the conversion methods to be implicit (and thus available with a single import but making your code more 'magic') or explicit (single import + adding calls to wrap/unwrap methods).

Total overhead: centralized conversion methods, assuming you write them yourself = implementation of elements(), and in the iterator, next() and hasNext(). One import per module that uses the conversions, and optionally, explicit calls to perform the conversion.