News for hackers. Stuff that matters.
Re:Scala Native by bad_user on Tuesday August 20, 2019 @01:07AM (#20743998)
For me Scala was never about using a Java++.

If you want Java++, the best Java++ is still Java with a bunch of libraries. You don't need a new language for that.

Kotlin's succes is effectively because Google was late to port Java 8 to Android. A fine language btw, but it will either become more like Scala, or it will wither away eventually. My bet is in it becoming more like Scala, as evidenced by arrow-kt.io

Scala has a blend of features that makes it the most expressive mainstream functional programming language, most importantly ... implicits, by which you can model typeclasses and higher kinded types.

And in Scala we've got an active community of FP libraries. Actual FP, emphasizing referential transparency, with abstractions built for suspending effects.

It's a little known fact but the kind of FP programming we do in Scala tends to be more pure than what happens in OCaml, F#, Erlang, Clojure and others.

Also, we have a Scala to Javascript compiler, all the tooling works with it and we've got an ecosystem of libraries cross-compiled to Javascript.

As for Scala Native, it has its place. The problem has been lack of manpower to bring it to the maturity that Scala.js is at.

Re:Scala Native by willtim on Tuesday August 20, 2019 @02:40AM (#20744350)
> It's a little known fact but the kind of FP programming we do in Scala tends to be more pure than what happens in OCaml, F#, Erlang, Clojure and others.

I have only dabbled in Scala, but IMHO it's more suited as an OCaml with first-class modules. Why not use Haskell, if you don't need the JVM?

Re:Scala Native by bad_user on Tuesday August 20, 2019 @03:08AM (#20744477)
Compared with OCaml, Scala can express type classes and has higher-kinded types. Many abstractions that are easy to express in Scala are in fact hard to express in OCaml.

For-comprehensions are worse than Haskell's do-notation or compared with F#'s computation expressions, but the list ends there. In practice they work well and at least Scala has monadic for-comprehensions. How many other languages can claim that?

As for performance, I encourage you to take a look at the state of the art. Working with our IO Monads has better performance than many abstractions that people now take for granted, like most Future/Promise implementations.

I build systems that are super stressed by incoming traffic and Scala's performance is awesome. Worse than bare metal Java of course, but when you compare it with high level Java frameworks or with Python/Ruby/Javascript/what have you, you'd actually be surprised by how better Scala FP is ;-)

As for Haskell, I like the language, but it's super fragmented, everyone has its own Prelude and favorite language extensions, extensions that are sometimes in conflict with other extensions and the tooling is a mess. Also laziness is cool, but performance gets hard to predict. We have the same problem in Scala when we are using lazy abstractions actually, the difference being that Scala is opt-in instead of opt-out.

With Scala, even if you're targeting JS instead of the JVM, you still use the same tools.

And I even like the language better. Scala 3 will fix many annoyances I have, including adding untagged unions and GADTs that are based on ADTs, in other words nicer than Haskell.

PureScript I would like though, as it fixes some of Haskell's problems, maybe one day it won't be limited to JS.

Re:Scala Native by dm3 on Tuesday August 20, 2019 @04:38AM (#20744870)
> As for Haskell, I like the language, but it's super fragmented, everyone has its own Prelude and favorite language extensions, extensions that are sometimes in conflict with other extensions and the tooling is a mess. Also laziness is cool, but performance gets hard to predict. We have the same problem in Scala when we are using lazy abstractions actually, the difference being that Scala is opt-in instead of opt-out.

Not an expert in Haskell, nor Scala - only dabbling. However, the above could be repeated verbatim after replacing Haskell with Scala, couldn't it? You can write Java++, Haskell-- or any combination in between. Use one of the several FP stacks or build tools.

I think both Scala, Haskell and C++ can compete for the name of the most complicated, fragmented and diverse language and ecosystem in existence.

Re:Scala Native by bad_user on Tuesday August 20, 2019 @06:26AM (#20745324)
I think people are too quick to judge languages.

If I tell you that Haskell has a fragmentation problem, I feel good about telling you that because I actually have experience with it.

However Haskell is still a language that I'd pick over Java, Go, JavaScript or any of the mainstream languages for that matter and I'd be willing to put my reputation on the line for that choice.

I also worked with C++. To see people compare Scala and Haskell with C++, kind of rubs me the wrong way.

And unfortunately such opinions stay on the Internet forever, are picked up by beginners and repeated verbatim.

So no, there's a huge difference between Scala, Haskell and C++. For one the former wouldn't lead to stupid and disastrous bugs like Heartbleed, whereas C++ can and routinely does. By comparison when well typed Scala or Haskell programs compile, the defect rate tends to be really low.

I'm seriously thinking about starting a course in how badly and easily you can fuck up in C/C++, for people that make unfair comparissons with them, making life hard for their managers :-)

Also just to get this out of the way... the problem in Scala are actually the Java refugees going gung-ho on OOP. And the FP people, because they tend to be more experienced, are the ones cleaning up the mess.

And I like that. You know why? Because Scala makes it possible to introduce FP gradually, without an organization wide commitment. In the company I'm working for, a language like Haskell would never fly, but Scala does.

Also in case you haven't noticed, FP is spreading.

- in Typescript/JS you have fantasy-land and fp-js

- in Kotlin you have Arrow

The difference is that you don't get the nice type system to support those abstractions well, so you also get the weird HKT and type class encodings to go with it. Although in fairness the Arrow guys are working on compiler plugins for better supporting type classes and the HKT encoding that they use.

So if you're conservative about adopting FP, language choice will not really protect you ;-)

Re:Scala Native by dm3 on Tuesday August 20, 2019 @09:11AM (#20746560)
Thanks for the answer.

To be clear, I wasn't comparing languages in terms of correctness of code you could potentially produce. Of course C++ is the worst on this metric. However, it has its own niche in low-latency setting where I can't see anything else replacing C++ any time soon.

Re:Scala Native by AzzieElbab on Tuesday August 20, 2019 @07:18AM (#20745603)
"So if you're conservative about adopting FP, language choice will not really protect you ;-)" Well, there is always Go and Cobol

Otherwise, exactly on the target. I hear java is getting continuations and tail call elimination soon

Re:Scala Native by dogweather on Tuesday August 20, 2019 @01:10PM (#20749334)
Haskell and Scala share complicated and fragmented programming styles. But Haskell has additional dimensions of complications (and thus fragmentation) due to:

1) Many compiler-option language extensions: https://downloads.haskell.org/~ghc/8.2.2/docs/html/users_gui... --- these add new language syntax and deep features. They radically change the meaning of the code you're reading.

2) Multiple competing standard library collections ("preludes"): https://guide.aelve.com/haskell/alternative-preludes-zr69k1h...

3) Haskell's language spec ceased development a decade or so ago. So the above diversions are never rolled back into the language. Instead, all forward development to Haskell is done in the form of new compiler options.

I'm not too familiar with Scala, but I'm pretty sure it doesn't suffer from these problems.

There are even more sources of Haskell fragmentation, such as many competing methods of error handling, input validation, and data records.

(I'm a Haskell user who wishes this all weren't the case.)

Re:Scala Native by mark_l_watson on Tuesday August 20, 2019 @09:50AM (#20747006)
re: “ As for Haskell, I like the language, but it's super fragmented, everyone has its own Prelude and favorite language extensions....”

I really like Haskell, but this aspect of the use of Haskell also bothers me. I use a small subset of Haskell and language extensions, a small subset that I am happy and productive with, but it takes me a lot of effort to understand other people’s code.

Re:Scala Native by dllthomas on Tuesday August 20, 2019 @10:36PM (#20754134)
> everyone has its own Prelude

In my Haskell experience (including some professional experience) this isn't the case very often at all (maybe not even as often as it should be).

(Which is not to say that there aren't some problems with fragmentation elsewhere in Haskell's ecosystem)

Re:Scala Native by tome on Tuesday August 20, 2019 @01:56PM (#20749866)
> extensions that are sometimes in conflict with other extensions

Could you name two widely-used extensions that conflict with each other in a non-trivial way? I've used Haskell for several years and I've never come across any.

Re:Scala Native by weberc2 on Tuesday August 20, 2019 @02:13PM (#20750099)
Regarding purescript, I thought I saw a post on the other day that said it now has C++ and Go backends.
Re:Scala Native by willtim on Tuesday August 20, 2019 @04:41AM (#20744883)
Thanks for the detailed reply!
Re:Scala Native by idnefju on Tuesday August 20, 2019 @01:51AM (#20744169)
> It's a little known fact but the kind of FP programming we do in Scala tends to be more pure than what happens in OCaml, F#, Erlang, Clojure and others.

What do you mean by pure exactly? IO Monad? Simply no side effects?

Re:Scala Native by bad_user on Tuesday August 20, 2019 @02:08AM (#20744224)
Yes. Many libraries in the FP Scala community are concerned with modeling effects in a pure way.
Re:Scala Native by idnefju on Tuesday August 20, 2019 @02:22AM (#20744274)
Oh interesting view. It's funny since Scala's author himself doesn't consider the IO monad to be "pure".

> “The IO monad does not make a function pure. It just makes it obvious that it’s impure.”

https://groups.google.com/forum/#!topic/scala-debate/xYlUlQA...

Re:Scala Native by willtim on Tuesday August 20, 2019 @02:33AM (#20744325)
It's a pure function because it doesn't do any IO. It returns an action that, when run, performs the IO. Because it's a pure function, we have referential transparency, we can safely replace the function call with its computed value (the action) anywhere in the program.
Re:Scala Native by victorNicollet on Tuesday August 20, 2019 @02:49AM (#20744396)
In a typical IO function, the first 10% of the code returns a monad-bind that holds the remaining 90% of the code in a closure. The pieces are pure, but the whole isn't meaningfully pure.
Re:Scala Native by bad_user on Tuesday August 20, 2019 @03:22AM (#20744549)
A function returning IO preserves referential transparency.

    fn() + fn()

    // ----

    val a = fn()
    a + a
Are the two programs above equivalent? For a function returning IO, they are. For a function that's side effectful, they are not.

(As an exercise for the reader, think of our function here returning Future/Promise instead of an IO, how would that change the program?)

This is a definition of purity that you can work with. The trap that people fall in is to talk about fiction essentially. What is "meaningful" anyway? If you don't give it a definition, is it meaningful to talk about what's meaningful?

I agree that a function returning IO is opaque. You can't reinterpret it, it's no longer a plan that you can change the interpreter for, but something concrete. There are of course better abstractions for dealing with effects in a way as to make them less opaque ... like the Free Monad, or Eff.

Many of them have been expressed in Scala as well.

Re:Scala Native by victorNicollet on Tuesday August 20, 2019 @06:00AM (#20745213)
Purity is not a goal in itself, its purpose (its meaning) is to help me answer useful questions about the behaviour of the program.

In a typical IO function, `fn()` only gives me 10% of the code in `fn`: the part up to the first bind. To get the rest, I need to `do` it, and this is where purity is no longer meaningful:

    a <- fn "a"
    b <- fn "b"
Can I swap these two lines ? The IO monad tells me there might be consequences, but what are they ? Another example:

    foo fn 
Will `foo` trigger the IO effects of `fn` zero, one or more times ?

I believe these are meaningful questions, and yet, a program built from pure functions can answer them no better than an imperative program.

Re:Scala Native by bad_user on Tuesday August 20, 2019 @06:38AM (#20745389)
> "Purity is not a goal in itself"

Agreed. However having referential transparency for IO does help. Let me explain...

The program you mentioned has one clear property: those two computations will execute sequentially.

This sequence of executing operations becomes independent of evaluation via IO. And if you want parallelism, you need to make it explicit.

    val a = fn(1)
    val b = fn(2)

    for {
      r1 <- a
      r2 <- b
    } yield r1 + r2
For IO this always has the same execution characteristic. "B" will execute after "A". You have a clear happens-before relationship.

As an exercise:

1. think of what happens if that function returns a Future/Promise

2. think of what happens if that function is synchronous, but still side effectful

In both cases the actual order of execution is not guaranteed. In the second case the ordering is only guaranteed from the point of view of the current thread only. And this is interesting b/c the only way to force ordering in a multi-threaded context, besides memory barriers which are a runtime trick, is to create a data dependence. In other words, while this code doesn't guarantee visibility with IO, it does have stronger ordering guarantees than any side effectful code you can throw in there.

You're a little unfair here btw. If the two operations here are not dependent on each other, then the Monad's flatMap/bind isn't the operation you want, since Monads literally describe sequencing. And you want sequencing in case order of execution does matter.

In other words, when you see a sequence described via bind/flatMap, you have to assume that the order is relevant, because the author could've done this instead, which is self explanatory:

    (a, b).parMapN { (r1, r2) =>
       r1 + r2
    }
And now they are executed in parallel, with no related evaluation gotchas (exposing the API in the Cats library here).

So to say that IO doesn't give you any useful property here is factually untrue. The obvious gain is that you look at an expression and know exactly how and when it will execute.

Re:Scala Native by bad_user on Tuesday August 20, 2019 @03:15AM (#20744508)
I encourage you to learn more about IO:

https://typelevel.org/cats-effect/datatypes/io.html

Also see my comment here:

https://news.ycombinator.com/item?id=20744549

Re:Scala Native by jjtheblunt on Tuesday August 20, 2019 @01:58PM (#20749894)
"implicits" seems a polarizing feature