(Please don't say + to concatenate strings, because everyone knows its terrible, its there for Java compatibility)
(Please don't say + to concatenate strings, because everyone knows its terrible, its there for Java compatibility)
When creating a library should my functionality exist explicitly on the types? As extension methods on an implicit? As type classes?
When should I use infix/prefix notation? When should I use . syntax vs no .? What does _ mean in this particular line of code? Is an allocation happening for this lambda or not?
Why are map/flatmap/filter magical? Why are for comprehensions part of the language for those but not for type classes?
All of these kinds of questions are really hard to answer and I've been programming Scala in production for years.
Other complaints I have are about the mess that is the collections library, the push for actors when they are generally a bad solution, an emphasis on algebraic types without providing Union types, and all the opportunity costs represented in sbt (which is finally passable but no better) and Scala IDE.
Don't get me wrong, if you are targeting the JVM & want strong typing (I do), Scala is the best language for the job, but even for someone who uses it every day and is pretty expert there are some confusing corners & no 2 developers seem to write code the same way, so there is a price to be paid for that.
1) In general, I think that going parallel should be an architectural decision. On current commodity architectures it doesn't buy people as much as they think it does, and can in many cases over complicate code. Actors hide this complexity, but don't actually remove it. People think actors give them free license to add tons of threads when they shouldn't.
2) Actor code tends to mix business logic with threading logic, precisely what we should be trying to avoid.
3) The actor model subtly conflates publisher/consumer models which tend to decompose and perform better in parallel situations.
Normally, for calculation style parallelism I prefer future/promises and for event style parallelism I prefer single writer/multiple consumer based shared memory.
- Covariance / Contravariance - Implicit Parameters - Implicit Conversions - and also mentioned here, Structural typing.
However now that i've spent time with the language, seen these in action and used them myself I see the reason why they exist and embrace them. I can see why this would be a common complaint against Scala and can be a barrier for a lot, but I think the language is worth investing time in learning, at least for me.
BTW: Kotlin has copied it and noone complains it is too complex :D
As of implicit parameters / implicit objects - ok, but what do you suggest as a replacement so that map/filter/reduce preserve types correctly? Or how do you do type-classes then?
How did delegates use variance? I've never been terribly clear on the whole delegates concept - they're like first class functions, except nominally typed and weird.
I don't have a specific answer to this question, but I do want to warn you that this is a dangerous line of reasoning. Given a complicated object like Scala or C++, you can easily have a situation where each individual element is necessary to support two or three other elements of the overall structure, yet, the overall structure can still be too complicated.
And to be clear, I'm not even saying you're wrong. Maybe there isn't a better choice. Scala's choice to be compatible with Java creates a very strange design situation. I'm just saying, this isn't a safe line of reasoning. I think it makes it very easy to become very short-sighted about your options by encouraging you to always be very locally focused.
(That's the answer I'd give if someone asked me this question)
trait Foo {
def bar(): Int
}
and 3rd party library had final class FooBar extends java.lang.Object {
public int bar() { /** **/ }
}
you could simply define your methods to take in a: type BarAble = { def bar():Int }
But obviously if the library class is not final, you can simply do: type ThirdPartyFoo = FooBar with Foo
ThirdPartyFoo <: FooIt's a feature that you will use directly maybe once a year when adding it to a library, but I then use that library (and indirectly that feature) virtually every day. YMMV but we've found it very useful.
The problem isn't + string-concat, it's silently casting numerics into strings.
"foo" + 6 + 6
Should be a compiler-error. "foo" + 6 + 6
>Should be a compiler-error.Why? "foo" is already a string, getting "foo66" from that makes perfect sense to me.
6 + "foo" though would be crazy.
http://stackoverflow.com/a/267496/486561 http://stackoverflow.com/a/480362/486561
http://benchmarksgame.alioth.debian.org/u64q/benchmark.php?t...
.NET is Windows-only, which is a significant limitation compared to the JVM. I don't think better performance on Windows -- even assuming going to CLR instead of JVM would provide that -- is a good reason for Scala to move to the CLR as the primary target.
(Still, it would be nice to have specialized generic containers for some primitive types in the JVM)
But Xamarin's porting of Java to C# to run Android on Mono without the JVM did show a rather large perf increase. I'd assume that's mostly generics eliminating boxing.
But you may be right that this might not be viable to run fast enough for JIT on a large codebase. Obviously you could tail-call enable every call that's eligible, but that probably doesn't generate optimal code. OTOH, they have tracing in the JIT for hotspot stuff, right? So if the tracing part counted how many call loops it had hit, it could decide to implement tailcalls in that path. Or perhaps it invokes analysis when the stack gets to be 75% full.
For example, consider an F#-like language on the JVM. Given the definition `let apply f x = f x`, you could imagine `apply` getting called in all sorts of contexts that don't result in unbounded recursion, so a hotspot-like system would not generate a tail call when compiling the method given the first N invocations. But then if another function is defined as `let rec loop n = if n < 1 then n else apply loop (n-1)` and invoked as `loop 10000000`, then the lack of a tail call in `apply` is fatal.
Of course it'd be better for the JVM to support this in bytecode, just like generics, stack allocation, and pointers. But it seems to me that if there was a real solid need for TCO then a JVM could implement it with tunable heuristics (most Java code doesn't need TCO, so if your code really depends on it in complex scenarios, you can always pass a -XXTcoInspectionDepth argument.)
The CLR branch, IIRC, was dropped because the CLRs reified generics -- which are better than erasure so long as your type system fits exactly what the CLR assumes -- are a very bad fit with Scala's more robust type system, which leaves you stuck with a bad interop story if you don't want to radically change Scala's type system to fit the CLR's assumptions.