HN user

happy_dino

145 karma
Posts0
Comments146
View on HN
No posts found.
  > It seems we have different definitions of what type 
  > inference, higher order functions and Turing 
  > completeness means. :-)
I don't think so. The definitions are pretty much standard and those are the ones I'm using.

I think we can agree that the way Java supports those features ranges between unusable and pretty terrible in practice, but that's not what your claims were about.

Your notion of Scala having more features than a "standard" mainstream language might even be correct, it is just that the points you have given don't support your point here.

  > Regarding coroutines in Java: I don't know if libraries
  > using native continuation mechanisms or bytecode
  > manipulations prove that Java (the language) has
  > continuation support. :-)
Then Scala doesn't have continuation support either. Whatever definition is applied, it needs to be applied consistently.
  > I don't have anything against Scala.
I never suggested that and even if you had something against Scala, it would be perfectly fine – for me and probably for everyone else.

It's just that you have claimed a few things which I think are incorrect, either factually or in the way they were worded, and I'm offering some data points against it. This all happens in good faith and in the hope that we both will have gained some knowledge at the end of this discussion.

  > As you noticed with Java 8 Java is already borrowing a lot
  > of useful things from Scala. I am sure conservative
  > corporate decision makers will see less and less reasons
  > to switch to Scala as time passes by.
I think most Scala users would agree that Java 8 copying Scala is a good thing, because it strongly validates what the designers and users of Scala have been doing for the last 10 years. With Java moving closer to Scala, adopting Scala becomes a lot easier from a management POV which in turn removes a lot of the concerns corporate decision makers have.
  > If I have a function: def upcase(s: String): String [...]
  > A unit test can check if the returned string is really
  > the upcase version of the input parameter.

  def upcase(s: String): UppercasedString
Now the compiler can check it, too.

Go's GC is non-moving, exactly because they can't precisely know what a pointer is and what is just some random int.

So it's basically as if all objects are pinned in Go. I don't expect that to change. There are probably tons of Go code out there which will break in response to a change.

I guess it will be pushed back to some mystical "2.0" release, along with Generics.

Looks like you just managed to disprove my earlier claim:

  > Before I learned about Clojure, I certainly wouldn't have 
  > believed it if someone told me that there was a Lisp-like 
  > language without the pretentious assholes.
Too bad.
  > Java has no type inference, higher order functions,
  > coroutines, implicits (it has some standard implicit
  > conversions but not implicit conversions that can be
  > added by the user) and no Turing complete type system.
Type inference in Java:
  int bar = new Object(){ int foo = 42; }.foo;
  // Magic? No. Type inference.
Higher order functions in Java:
  http://download.java.net/jdk8/docs/api/java/util/stream/Stream.html
  Looks pretty higher-order to me.
  Also possible in older version in Java with stuff like Google Guava or FJ.
Coroutines in Java:
  http://stackoverflow.com/questions/2846428/available-coroutine-libraries-in-java
Implicits:
  Having them built into the language is even worse.
  In Scala you could just de-import them and have them gone.
  Anyway, pick C# as an example instead if you want to have
  user-defined implicit conversions.
No Turing complete type system:
  interface Interface<T> {}
  class Bang<T> implements Interface<Interface<? super Bang<Bang<T>>>> {
      static void bang() {
          Interface<? super Bang<Byte>> bang = new Bang<Byte>();
      }
  }

  Looks pretty undecidable to me. In a way, it is even
  worse than other languages: You are unable to tell
  whether the type checker will terminate in finite time
  (like some other languages), but don't get any additional
  expressivness in return (unlike those other languages).


  > As a side effect this will also find all type errors
  > a compiler will find.
No, absolutely not.
  > I have programmed a lot in Java and also in dynamic
  > programming languages and in my opinion type errors
  > just don't happen often enough to justify the
  > additional amount of work and complexity that comes
  > with static type systems.
This comment certainly explains a lot. You are suffering from the "I used Java and Java is statically typed and it sucks, therefore all statically typed languages have to suck" fallacy.

I guess it depends on where one comes from. If one compares Scala to Scheme, sure, Scheme is ridiculously simple compared to Scala.

But if one compares Scala to languages which are actually used in the wild like Java, C#, PHP or C++; Scala's footprint is just incredibly small.

All of the features you mentioned are available in languages like Java or C#, too. The difference is that in most cases the implementation is so poor and incoherent, that the feature is next to useless.

I guess one just "sees" more language features being used in Scala, because almost everything which ships in the language makes some sense, while in Java/C#/PHP/C++ you have tons of utterly useless "features" which don't add any benefit, but still force people to learn them in case somebody else used them.

I have never seen "On a sufficiently big project with one or more extra clever developers most probably every feature will be used" happen in real life. In my experience one of the strengths of Scala is the way one can use some advanced feature where it makes sense, without having it bleed through the whole code. Compare that with Java's, C#'s "Oh, you used some complicated Generic type over there? Guess what, we will make every user suffer from it throughout your whole code base!"

In a sense, I prefer a language (Scala) which ships with 100 features where 90 of them make sense to a language which ships with 400 features where only 50 make sense, like C# (multiply "feature" count by 10 for C++).

  > And I don't need a compiler to catch errors that a unit test would also catch.
Well, using the compiler means that it will also catch errors which you haven't written unit tests for. Tests can't prove the absence of certain categories of errors, compilers can.
  > but it will win in the next 15 years in a major way, 
  > because it is already one of the most interesting
the most interesting ... what?

Anyway, I think they have already won in a major way: The managed to build a community which is supportive and friendly. This is a huge deal when you have a look at the poisonous behaviours of individuals and the wide-spread arrogance typical in most Lisp communities.

Before I learned about Clojure, I certainly wouldn't have believed it if someone told me that there was a Lisp-like language without the pretentious assholes.

  > An enterprise Scala project, for example, is typically 
  > going to present the frustrations that come with 
  > components that live outside the language. Learning Scala 
  > isn’t that bad, but Maven and Spring and Hibernate? Ouch. 
  > In Clojure, most of the typically “external” needs are 
  > provided with idiomatic libraries that can be reasoned 
  > about within the language.
That doesn't make much sense. One can do exactly the same in Scala. The big improvement on Clojure is that it is completely pain-free and seamless to keep the old components around and migrate gradually to better solutions (or just keep the legacy parts which work – why bother changing it?).
  > while every static language worth its salt has an 
  > interactive mode (“REPL”) it doesn’t have the same
  > first-class-citizen feel
Maybe this has changed, but the last time I used Clojure's REPL, it was completely unusable, with basic things like auto-completion, history and navigation being completely non-functional.

I think the opinion voiced in the article is interesting, but past experience tells us that the chances of a Lisp to get even slightly popular is low to non-existing.

While I can't speak of traction in enterprises in Germany, I wonder what the notion of "Scala with its everything and the kitchen sink feature set" is about.

This seems to be a popular meme, right until someone asks for details – crickets chirp.

As a general policy, if I spend time explaining things I require people to do some homework on their own.

This way people who are lazy, whose interest is just strong enough to make ridiculous claims and complaints but don't actually care about the topic at hand, don't get things for free.

I protect my investment and everyone wins.

How easy is it to find a Scala developer if you need to expand your team compared to a Java developer?

How easy is it to find a GOOD developer? Much easier with Scala. It's not like wading through hundreds of Java resumes and interviewing them is free.

In addition, Scala tends to run slower than Java which can have a further cost if you're scaling to many servers.

This depends on so much different factors in both Java and Scala that I'm happy to dismiss this claim as “not true”.

Porting Java code to Android is also far easier than porting Scala code.

Really? Is there anything more to do than ProGuarding and dexing the existing code, both in Java and Scala?

I am still seeking the legendary JVM implementation with TCO.

  scala> :paste
  // Entering paste mode (ctrl-D to finish)

  object TCO extends App {
    def stackSize = Thread.currentThread.getStackTrace.length
    def printStackSizeMessageOutside() =
      println(s"$stackSize stackframes outside of the mutually recursive calls")
    def printStackSizeMessageInside() =
      println(s"$stackSize stackframes inside the mutually recursive calls")

    def mutuallyRecursiveAdd1(a: Long, b: Long): Long =
      if (b == 0) {
        printStackSizeMessageInside()
        a
      } else
        mutuallyRecursiveAdd2(a+1, b-1)
  
    def mutuallyRecursiveAdd2(a: Long, b: Long): Long =
      if (b == 0) {
        printStackSizeMessageInside()
        a
      } else
        mutuallyRecursiveAdd1(a+1, b-1)
  
    printStackSizeMessageOutside()
    mutuallyRecursiveAdd1(23, 10000000)
  }

  // Exiting paste mode, now interpreting.

  defined object TCO

  scala> TCO main null
  We have 29 stackframes outside of the mutually recursive calls
  We have 30 stackframes inside the mutually recursive calls
  // Some example methods which might spend waiting for other
  // services (calling the database, sending emails).

  def getEMailForUsername(username: String) =
    future { DB.Users.find(_.name == username).get.email }

  def sendPassordRecoveryMail(email: EMail, message: String) =
    future { SMTPService.send(email, message) }

  // Future/Promises API:
  def resetPassword(username: String) =
    for {
      email <- getEMailForUsername(username)
      result <- sendPassordRecoveryMail(email, "some message")
    } yield result


  // Async API:
  def resetPassword(username: String) =
    async {
      val email = getEMailForUsername(username)
      val result = sendPassordRecoveryMail(email, "some message")
      await(result)
    }
@smegel: I don't see any “callback hell” or “code that does look like spaghetti” here. By the way, I'd love to see a link to “Scala's synchronous API” and that mystical “far less attractive callback based API”. Or are you making things up again?

[...] then it would be a different matter entirely

Have fun moving the goal posts around.

Java was created in the mid-90s before every man and his dog was trying to solve the c10k problem on a $5/month VPS. Hardly surprising.

So what? C10k isn't a hard thing to do on the JVM and it probably beats Go by a large margin in terms of latency and performance.

Why do you think Scala has both blocking, and "event based" (loop/react) API's?

Your point is ...? There are plenty of different libraries, because concurrency can be tackled in different ways. Use the right tool for the job. Unlike in Go, where you pretty much have to shoe-horn everything into “goroutines” or channels.

The lack of developers which run around and try to tell everyone that they found the silver bullet for solving concurrency in Scala is a sign of a mature community which has experience and expertise and doesn't just repeat whatever Rob Pike says like Go users seem to do all day long.

Quite possibly, you must have been living under a rock if you haven't heard of callback hell in Node.js.

Eh ... so what? It's not like Node's terrible approach is the only alternative to Go's approach. Claiming “A is the best, because B is even worse” just shows a complete lack of knowledge of existing solutions.

What is lacks (my original comment) is the ability to write event-based code using a synchronous, blocking style (without callbacks).

Again: No it doesn't. Do your research instead of claiming blatantly false things.

  C is easy as pie. It's the most fundamental language.

  Forth is a super-cool game. My kid already rocks on
  an HP-41 calculator (RPN). When I introduced him to
  Forth he literally said: "Wow! I can program in RPN!".

  Java, was a short stepping stone as I wanted to give
  him a quick taste of OO but not drown him in the
  details. He actually wrote a dozen little games with
  graphical interfaces and all. Great fun.

  Now with Python we are going through the Project Euler
  site problem by problem implementing solutions mostly
  in Python but then looking at C and Forth where it
  makes sense.

That would have been a sound choice ... in 1990. Since then, there has been a lot of progress in language design.

C is fundamental, but calling it “easy as pie”? 90% of C consists of undefined behaviour, just waiting to screw you over.

Forth ... why not some Lisp instead? I don't like Lisps in general, but they are at least not as completely obscure as Forth.

The designers of Java had some good ideas, but the execution of the language itself is terrible. Java is what gives OO a bad name, why not pick a language which is good at OO?

Python, well sounds sort of OK, at least no PHP or JavaScript.

====

I guess my choice would have been something like that:

- Assembler - ML/OCaml/ATS/Rust - Scala - Haskell

In any language implemented on the JVM (including Scala) you block an OS level thread.

Wrong. Whether JVM implementations use green threads or system threads is an implementation detail. There are implementations for both cases.

You realize that many JVM implementations started with green threads in the early days and abandoned them not much later? There is a reason for that.

The way languages without green thread support allow non-blocking, event based code is through callbacks, which can get pretty horrendous in large, complex programs.

Wrong. I repeat, the underlying threading model does not necessarily enforce some style of API.

I'm not sure why that is relevant (Actors seem a pretty core part of Scala)

Actors are a library, just like Scala's async/await, the Future/Promises library, the continuation library, Java's Fork/Join library.

Actually, Scala just replaced its “official” Actor library in the last release. Go will be stuck forever with its ad-hoc stuff which has been hard-coded into the language.

it is unsurprising that a mere library on top of the JVM is still constrained by the kind of concurrency supported by that platform, i.e. the lack of green threads

LOOOOOOOOOOOL. Since when are green threads the “new best thing ever!!!11!!”? Did I miss a memo here?

You know what? Wake me up when Go has fixed their broken scheduler. Until then, I just keep watching how the JVM embarrasses Go on pretty much every concurrency and scalability workload.

I just fear this "it must stop breaking things after 1.0" attitude some people have.

That's exactly what the death of a promising language looks like.

Those people should just go elsewhere, there are enough worse-is-better languages to pick from without dragging down yet another one.

Eh what? That's not right, that's not even wrong...

The style one can program in and the style it is implemented isn't connected the way you think it is.

And no, Scala "doesn't have" loop/react. Unlike Go, where people seemingly put random stuff into the language, it's just a bog-standard library.

Scala has neither operators nor operator overloading and I don't know any library which "encourages" doing those crazy things.

There are a few places where symbolic method names are used, and in pretty much every case, it is well-established prior art: +, -, *, /, etc for math operations, ! for sending actor messages (Erlang), &, | ,^ for bit operations (C and friends).

Regarding the type system ... well, the alternative is stuff like reflection and casting. Both introduce the possibility of runtime failures and make refactoring and reasoning a lot harder.

Sure, sometimes a well-placed I-assume-this-can-never-fail cast is exactly what one needs, but I'm happy that Scala gives developers another, safer option here.

Wow, no need to get so defensive.

You basically gave your child a job training, concentrating on technology which is popular today (and probably at the time when he is looking for a junior maintenance developer position, too). Nothing wrong with that.

If I decided to teach my child programming, I would certainly try and pick the best, most consistent, fun & exciting, state of the art technologies out there which would expand the mind of my child about what's possible today and inspire my kid to push the boundaries when he grows up (if he/she ever decides to pursue that career option).

Different decisions, and one could make the case for both.

Coffee is to JavaScript as Scala is to Java.

Considering how incredibly wrong and broken CoffeeScript's scoping is (at least the JavaScript designers realized that they messed up badly), I'd consider that an insult for Scala. :-)