Reasonable Scala Compiler
github.com
github.com
Sounds like they are intending it as a research effort and hope to make progress with the entire Scala community, not fork it.
I have been writing scala for 2 years, mostly in spark and flink and as much as I love parts of it, overall, the language is just not the most approachable. Some of the features are super valuable every once in a while, but I might gladly give some of them up for a streamlined language that is easier to get people started on (while not just writing imperative style Java with Scala syntax)
My other curiosity is compatibly. If I can compile a subset of my project much faster that doesn't need all of Scala, that seems like an okay place to be in.
Scala can be too hard sometimes.
Totally. Its interesting that they approach this from a compile speed angle, I wonder how much they are also considering the mental load of certain features.
This might become an interesting project for companies already doing Scala. New ones at this point will probably prefer Kotlin.
Then, when the developer has finished they can switch off "YOLO mode" and start playing whack a mole with the types, as needed, punctuated by longer compilation times.
Here's a testing analogy: My CI server runs all tests, every time. My local machine only runs the ones I tell it to run as if I change one small piece of an app then I'm not going to wait for the entire test suite to run.
It's not possible to actually build, because at the end of the day you are (presumably) using the implicit for something (e.g. JSON-serializing the value). You could explicitly pass ??? where the implicit is wanted to get a runtime failure where it's used. I guess it might be possible to have tooling do that "magically", but I'm not sure how useful that would be; if you're working on that particular area you can use ??? by hand, if you're not working on that area then you presumably won't be rebuilding it since you're presumably using incremental compilation anyway.
What is possible is to fail-fast when resolution fails, and not check for duplicates when resolution succeeds - one main reason for the blowup is that at every stage of recursive resolution you have to check whether the implicits were ambiguous. There's a proposed fix for that piece: https://github.com/scala/scala/pull/5649
Any concrete ideas? In my experience the parts people find intimidating often aren't actually language features, they're things some library or other implements.
I mean there are things I would remove from Scala if I were in charge - structural types (provided there was still a way to express partially applied types i.e. standardize kind-projector in the core language), Dynamic - but they don't tend to be the parts that trip people up.
Edit: should have keep reading before commenting. In their related work document:
>we are definitely not declaring Lightbend Scala dead. To the contrary, we view ourselves as complementary to Lightbend Scala and hope that our results will create new opportunities for the official compiler. We are planning to keep in contact with Lightbend to discuss our findings and facilitate technology transfer.
1. reasonable support of object oriented programming.
2. reasonable support of functional programming.
3. solid concurrency features.
4. runs comparable to native code.
5. simple to learn.
Even though it is not difficult to create such a language but we see a new language poping out every now and then and none of them try to solve these issues.https://github.com/apple/swift/blob/master/docs/proposals/Co...
In my limited experience Rust and Swift both suffer from boilerplate/ceremony you have in many other OOP languages (C# too). Static languages for you I guess - there are benefits too...
1. OOP: https://www.packtpub.com/mapt/book/application_development/9...
2. FP: https://blog.plan99.net/kotlin-fp-3bf63a17d64a
3. Concurrency: https://kotlinlang.org/docs/reference/coroutines.html
4. Native: https://github.com/JetBrains/kotlin-native
5. Simple: https://try.kotlinlang.org/
I think it really depends on your use case too. Kotlin is great for mobile apps and games, where coroutines are fantastic (see also C#/Unity there). For writing scalable web services, you need more control and resilience. There Elixir and Scala are the heavyweights.
Much less heavyweight than macros and easier to reason about.
Most Scala doesn't need macros (other than those inside shapeless) because Scala has a) higher-kinded-types, for/yield and an existing library for working with context-like types, and b) generic traversal of object graphs via shapeless. Between them those cover virtually all the use cases for annotation processing, macros or anything like that.
* https://github.com/adamw/macwire
* https://github.com/fthomas/refined
* https://github.com/adamw/quicklens
* https://github.com/scala/scala-async
* https://github.com/typelevel/machinist
Even for cases where inductive implicits can do the job, there is still a bit of a push to prototype with shapeless and then rewrite with direct derivations of your instances later on to improve compile times. See e.g. https://github.com/circe/circe-derivation.There are performance problems with inductive implicits in the current compiler; I'd rather see that fixed at the compiler level (I believe there's already a PR?) than see every library try to work around it. Actually I'd like to just build something like Shapeless' functionality into the language proper; I'd say e.g. case classes and sealed traits should have come with the equivalent of LabelledGeneric already.
We'll just have to disagree on these sorts of "power tools", I think.
Quicklens does a lot more for you than Shapeless's lenses, which to my knowledge not very many people are using for new projects at this point. I think once the Cats port lands, I'll be moving to Monocle for my own stuff, though (I think this will be the trend).
Of course, the compiler getting better about inductive implicts can only be a good thing, but I do think there may be some upper limit to what can be done short of an effort similar to what Eugene is taking on with Reasonable Scala, since they are using a typechecker as an unwitting computer when we program that way. The work that Miles did to improve inductive implicit performance is tremendously helpful but it does not fully solve the problem. As an example, my very-induction-heavy codebase compiles about twice as fast with his patch enabled. That's nothing to scoff at and is super-impressive for a single patch, but it doesn't make the problem evaporate.
I fully agree with you that it would be great if Generic-like stuff were baked into the language. To me, that sort of thing is the only compelling use-case for whitebox def macros. I feel like things would be better if we could just drop those.
* https://github.com/zalando/grafter
to your list.
Maybe for you but given how popular annotation processing is on the JVM (and especially on Android), plenty of people are reasoning with them just fine.
Actually, it's so popular and easy to use that it's slowly replacing reflection in pretty much every library I've seen.
Any myriad of FP (scalaz, cats), concurrency libraries (rx, akka)
scastie: https://scastie.scala-lang.org/
scala.js: https://www.scala-js.org/
This FP-focused fork of the Scala compiler: http://typelevel.org/scala/
The next gen Scala compiler called dotty: http://dotty.epfl.ch/
Twitter doesn't mention scala-native...
Turns out to be quite arduous:
- You ask for reasonable support for both object-oriented and functional programming, this already contradicts with the notion of state (that objects suppose to contain in OOP) and "stateless" ways of FP, let's ignore that for a moment
- FP means different things for different people - some would argue it has to have well thought type system, but what exactly that means? Is strongly but dynamically typed like in Clojure is okay (with added sugar like Clojure.spec)? Or it has to have static types? Does it have to have then type inference like in Elm? Or definitely it has to have algebraic data types like in Haskell? Or maybe dependent types like in Idris?
- Concurrency models vary too, for example: STM in Clojure and Haskell aren't exactly the same. Actor model in Erlang is a beast and sounds awesome on paper, but in real life process coordination may become a headache. Primitives based on CSP model are also known to have their own quirks. Concurrency in any language is never simple and straightforward.
- You're asking for an fast FP language - with immutable data structures and lazy/non-strict evaluation it's probably unrealistic to get it to run as fast as native code
- And "simple to learn" is also very subjective quality - for some Python is easy, but Clojure is hard. For some Haskell is not that difficult as people describe it. For some it feels like insurmountable mountain.
As you can see - it's not that simple. And we probably not gonna get a "perfect" language that suits everyone anytime soon.
It's difficult to agree with a definition of FP that doesn't require expressing as much computation as possible as function evaluation. Functions being mappings from values to values, having a rich set of values (not the same thing as objects!) is a prerequisite.
Scala, Common Lisp, C++, D, Clojure, F#, OCaml, Kotlin, etc. Those could all count or not depending on your subjective opinion.
The truth is, it is difficult to create the perfect language, and any sufficiently complete language will always start to have part of it that suffer in exchange.
Out of those, only OCaml really provides “reasonable” support for functional programming. The ability to manipulate compound values (say, lists or trees) directly, without using objects having a queryable physical identity, is of course a prerequisite.
> it is difficult to create the perfect language, and any sufficiently complete language (...)
Maybe the excessive amount of features is the problem in the first place.
And we're talking about a language dammit, not libraries or package managers. Let's have a good language first, then build the tools around it.
Personally, I like Haskell. It's great for 1 and 3, 4 is pretty acceptable and 2 gets thrown in the bin.
5 could do with some work, though.
1. Solid mix of functional programming and Object oriented programming (though FP is more important - I'd gladly give up inheritance if I get good support for interfaces and traits instead)
2. Static type checking
3. Good support for efficient immutable data structures.
4. Solid concurrency features
5. Easy cross-compilation to and interaction with JS
5a. Cross-compilation to iOS and Android would be nice but it's not a dealbreaker
6. Good tooling (i.e. IDE-support, package manager)
7. A solid standard library
8. An active open source community around it
9. Said open source community should contain a good web MVC framework (or sensibly pluggable modules to the same effect)
10. A REPL
11. Sensible compilation times
So far it looks to me like only Scala and Haskell are candidates - and it sounds like Scala really struggles with the compilation times. If Reason/ocaml gained more traction it might become a contender. And if I gave up on static type checking then Clojure would be an option. And if I settled for a sprinkling of functional programming instead of having that be the basis, then Kotlin or maybe C#. Any other suggestions?
For me, ES6+ is near ideal in terms of syntax and features if it had parallelism support.
1. About the strongest OOP support of any language which doesn’t have a dynamic or Scala-esque exotic type system. Also supports non-OOP imperative, unlike Java.
2. Linq is nigh-on the best FP support offered in any non-FP language’s standard library, and really is one of the best FP libraries period.
3. Invented async/await, by far the most ergonomic concurrency primitive yet created.
4. Fast and easy to tune for performance (stack-allocated value types which can also be passed by reference).
5. If you know Java or C++ you’ll be productive within minutes.
(I really mean F* as in 'F-star' language)
The first time I saw how pattern matching with regular expressions automatically extracted the matching bits I was sold.
I'd also miss block expressions. I keep wanting to write if-expressions (as opposed to if-statements) in every non-scala language I touch.
But I agree, c#/.net is a good alternative if you're used to the expressiveness of scala.
This feels like a bit of hyperbole. The actor model seems much more intuitive than async/await. Indeed, message passing between actors is how concurrency works in the real world (think about how people interact with each other).
You can write (compiler enforced) pure functional code, and the standard library is somewhat monadic.
I am afraid of Scala fragmentation. There is no way new compiler can be 100% compatible. Hopefully it will be tested on major projects, or there will be some official Scala Language spec.
It would be nice to add a switch into old scalac, which downgrades its features, to make it compatible with new scalac.
I believe Scala has too many features, and it will be very difficult to fix compilation speed. But there could be decend boost just by rewritting compiler from scratch. If anything we will get better error messages.
Compilation speed was major reason why Jetbrains started Kotlin.
Disclaimer: I worked with Scalac / IDE back in 2009. Kotlin fanatic.
Twitter has pretty big resources. It's probably feasible for them to spin up a build farm that runs their compiler against all active Scala projects on GitHub, measuring error count and compilation speed as they go along.
I, for one, think that an official language spec would do the language a lot of good. As it stands, it is sometimes difficult to separate bugs from features in scalac...
Martin Odersky & co have been focusing most of their effort the last few years on Dotty (aka Scala 3), which succeeded in giving in giving Scala a proven theoretical basis in exchange for a few esoteric typesystem features they couldn't prove. [2]
[1]: http://www.scala-lang.org/old/sites/default/files/linuxsoft_...
[2] http://www.scala-lang.org/blog/2016/02/03/essence-of-scala.h...
I think Jetbrains has some experience using that spec to implement the IDE's Scala typechecker. Long story short: years later, it still doesn't work.
I would be kind of concerned about the esoteric new features they added to Dotty, looks like the lesson has not been learned yet.
- "Numeric harmonization" which makes some of the existing issues with implicit numeric conversions even worse.
- Multiversal equality, which adds even more special rules to the implicit resolution algorithm, complicates the mental model of the language, is either extremely invasive or severely limited when applied to real-code, and falls apart when dealing with existing language features of Scala like variance.
- Addition of inline, which has absolutely no reason to be a new keyword.
- The tentative idea of adding T? for T|Null (as it appeared on some slides) which makes it obvious that no thought has been given to how the lessons of handling nulls apply to Scala.
Then we have enums, which are just poorly designed and executed, repeat the mistakes made with both case classes and scala.Enumeration, do not address the problems it is supposed to solve, fail to address actually valid existing problems, all while introducing not one, but two additional syntactic constructs which are unlike anything we had before.
On top of that we got incompatible additions in minor releases of 2.12:
- Additional places where commas can be added, which ignores one of the most common complaints about Scala: Too many syntactic variations to express the same thing.
- The addition of @showAsInfix which is a solution in search of a problem.
But at least unsound type projections got restricted, I guess. (That's the only major thing I can think of that will have a larger impact...)
Probably the removal of forSome and cleaning up existentials?
Which feels to me like you will miss one of the advantages of having a compiler in the first place - that it helps you write correct code.
To be fair, in an IDE you do get some of the compiler feedback in real time. But not for the whole code base, if you're working on things that have high coupling with other modules then it can be really painful. (I'm looking at you, Spray serialization!! Ugh)
If you are serious about your work and time than use serious hardware.
You don't see see F1 racers show up on race day with a Scooty Puff Jr..
(And bear in mind that Twitter has literally the largest Scala codebase in the world. Almost all scala programmers work on something an order of magnitude smaller, with correspondingly smaller compile times)
But faster compiled languages still _feel_ better.
Not for me. There are hot zones in my code that I dare not touch unless I want to trigger an extremely long recompile. This really sucks.
Could people who have had issues with compilation speed explain their workflow, I'd like to better understand the problem.
For example, here's my general workflow:
1. code in IntelliJ until the feature/fix is complete, and there aren't any red-wavy lines in my source tree
2. run `compile` in an already running sbt session.
As a result, I only find myself "waiting" for a compile a few times a day. And even then, because I'm using the incremental compiler it's usually only a few seconds.
The only reason I run the sbt compile at all is because the IntelliJ compiler is known to be a bit buggy, especially around things like implicit resolution and some of the more advanced features used for abstract programming.
I have seen CI builds take some time, but even then, in every project I've worked on, the complete compile-time is dwarfed by the time taken to run tests.
I'm not trying to dismiss problems that others have; I would love to learn more about them!
So you type your query using a Doobie SQL string interpolator...
sql"SELECT ItemId from dbo.Item WHERE IsOnSale = TRUE"
...but then you forget all of the ".query[Int].vector.transact(tx).unsafePerformSync" crap that you are supposed to tack onto the end of the string to actually run your query. What are your options?1. Type a '.' character in your IDE and watch it crash while the presentation compiler thrashes around, sifting through a combinatorial explosion of implicit values (or whatever it is that makes it so slow). You quickly learn to stop using autocomplete. In a sane world, this should take milliseconds and you should quickly get a list of methods to guide you down the right path.
2. Type a '.' and try to recompile. Wait 30 seconds. While you're waiting, what work can you possibly do??? None.
3. Stop what you're doing, open up The Book Of Doobie [2], try to remember which page has the syntax that you need for doing this one simple thing, go to that page, navigate to the right part of the webpage, read the crap, think a bit, copy/paste it into your code. This FEELS more productive than (2), but is it really?
This is just one example, maybe not terribly compelling, but it happens. People (well at least me) have a limited amount of memory for administrivial crap to hold in our heads while we try to get our work done. Tooling is supposed to help with that, but with Scala it really starts to get in the way. Flow state just isn't possible.
I have heard anecdotes of developers running two or more instances of scalac so that they can work on more than one feature at a time in order to not completely waste away their time. Imagine the context switching there, and having to pay attention to the little oven timer and switching context when one compiler is finally done recompiling the same code it already compiled hundreds of times.
[1] https://github.com/tpolecat/doobie
[2] http://tpolecat.github.io/doobie-scalaz-0.4.2/00-index.html
Abstraction isn't free in Scala, you pay for the features used; tooling suffers as a result, thus projects like Twitter's RSC come into being.
You may want to checkout Quill, or Perhaps Slick (though the latter I suspect is similarly IDE challenged). Barring that, give your IDE loads of RAM.
I'm curious how a faster scalac would help in this case though. Perhaps I'm missing something, but scalac's errors don't really facilitate this kind of API exploration.
I completely agree that exploring an API (because who wants to memorise the standard library and API of all your dependencies) in IntelliJ is often quite cumbersome. One trick I've come to lean on a lot is to type '.ensur' to determine the type of the current term; this causes IntelliJ to present the method signature for 'ensuring', which is available (implicitly) on everything (except Nothing), showing the current type in its return type.
I haven't heard about this. Can you give a reference please?
and there seem to be open source projects like vmkit, https://github.com/ReadyTalk/avian that are somewhere in between.
RAM is cheap nowadays, and the number one reason I want a fast compiler is to speed up my feedback cycle between making a change and evaluating the effects of the change. So I want something that squats on a large chunk of RAM and works in parallel with me, updating with every edit I make.
Intellij implemented a SBT Shell in 2017.1, so it will keep the same SBT session going between passes also.
I'm talking about something much more real time. I want the parser to keep everything hot, updating every time I hit a key. And whenever I get to anything that the parser approves of, downstream stages, which also keep everything hot, dynamically update all of their structures, revising object files as they go.
Batch orientation is great, and I understand why compilers started there. But I want something that moves beyond that. It's sort of the difference between a batch-oriented rendering system like TeX or early word processing versus a modern WYSIWYG word processing setup, where we burn resources prodigiously to give users much faster feedback loops.
The JIT works on Java bytecode. Java also has a similar compiler (javac) from Java -> bytecode.
Either stick to the real Scala or switch to Java or Kotlin, but writing your own language is a failure waiting to happen.
I give this project a few more months before it gets canceled.
Hack/HHVM was developed by Facebook to modernize PHP.
There are plenty of cases where organizations successfully developed their own languages/compilers that gave them advantages. It's insane only if you have no good reason to do it. This sounds like they have a need: compile times are slow.
One needn't extend the same consideration to, say, fogcreek...
Yes but why use PHP in the first place? It's not the right tool for something like Facebook.
The point is: developing your own language to ship your apps is crazy.
If you insist on them "creating a new language" then say that they created a new language to speed up development, not to ship their apps. They were already shopping their apps. This is an optimization that helps them speed up development on their existing codebase.
> We are planning to start small with a trivial subset of Scala and then gradually add features, carefully measuring their impact on compilation performance
It will be a while before they reach parity with Scala, and I'll bet the project will be canceled before they even come close.
(Hint: no. http://asmjs.org/faq.html )
Also,
> The point is: developing your own language to ship your apps is crazy.
It's crazy until you get to Facebook (PHP -> Hack) / Google (Go/Dart) /Twitter scale, then it starts looking like a really good idea.
I'm of the opinion that developing new, purpose-built languages (or extending existing ones) is a strategy that isn't given as much consideration as it should.
2) If they can speed up Scala compile times by 5 minutes a day (extremely conservative -- compilation times tend towards 1s per file), across even 1,000 developers (Twitter had around 2000 when I was there) that immediately funds a 5+ person development team. This isn't the sort of thing you throw a huge team at, anyway.
3) It helps with recruiting talent who is looking to work in environments that have strong type safety, or who just want to work for companies willing to invest time in making their software engineers more productive.
JetBrains is in the business of IDEs and similar programmer tools. Kotlin fits right in with the rest of their business.
Imagine if JetBrains produced a chatting program, because their engineers were not satisfied with the existing options.
:)
ah yes rewriting in a new language, the classic not-insane approach
If the options are "Keep writing in Scala", "Port to Kotlin" and "Write a Scala compiler", the latter is clearly the worst and most costly of all.