Earlier quoted context omitted.
Yeah the extreme FP stuff works for some people, but not others, and that subcommunity has traditionally been very loud. I've been pushing hard on using Scala in a more hybrid way over the years, first with my open source libraries and then with my book Hands-on Scala. I think I've had some success in pushing this. There's definitely been a shift in the community in this direction. While the hardcore-FP folks are sti…
In my view though, Kotlin is just a much better version of that. But of course if you have lots of scala investment already, it makes more sense to do it within scala itself.
From First Principles: Why Scala?
301–310 of 342 posts
Re: From First Principles: Why Scala?
#302> In contrast, cross-compilers for dynamic languages like Clojure tend to have a long-list of caveats and incompatibilites I don't think the author fully comprehended the linked resource (namely https://clojurescript.org/about/differences ). Perhaps he just noted the its size. A good chunk of the document lists things in common, not differences. The actual differences have nothing to do with dynamic typing and are de…
> - don't pretend the JVM and JS have identical runtimes when it comes to concurrency or numerics. Clojure is a language, not a platform abstraction. > - Emit efficient, optimally minifiable javascript code, at the cost of offering something less traditionally lisp-y when it comes to eval, macros, and other forms of code loading. Those are still possible, but some discipline is imposed. This is exactly the kind of th…
The big difference is the interop, and from your link with Scala.js it seems that's also true of it.
I'd say in practice, where ClojureScript and Scala.js maybe can differ a bit is that idiomatic Clojure itself relies a lot more on interop than Scala. So probably more Scala code doesn't depend on Java interop and thus can be more easily ported to Scala.js, whereas more Clojure code relies on interop making it more difficult to port to ClojureScript.
The other big difference is that Clojure supports runtime macros and eval, and those would require the compiler be bundled with your frontend app, which would increase the bundle size a lot. So ClojureScript needs to drop some of the dynamism. It's very rare to have Clojure code that actually depends on this though.
Overall in practice, what you'd want to share between backend and frontend is sharable as-is between Clojure and ClojureScript, which is all that's really needed. You'll build a React JS based frontend in ClojureScript, and share data-model, validation, transforms over it between backend and frontend. And you'll want your render functions to be shared between them as well so you can do server side hydration for React.
P.S.: I also want to point out there is a camaraderie between ClojureScript and Scala.js, and the devs exchange ideas, taking inspiration from one another as well. Since they face a lot of the same challenges.
Re: From First Principles: Why Scala?
#303Earlier quoted context omitted.
Yes, it is a side-effect - and does make the code impure; but it's an /exceptional/ flow like OOM, infinite looping, stack overflows which also break equational reasoning. My argument is that as a programmer you /choose/ the base lemmas which you're comfortable with - with an exception you're saying for a large swathe of your code, it will assume a lemma. When is /does/ break you get to point the finger at it with a…
This is spot on! Way too often in Scala codebases, which tend to wrap IO calls in Future or similar is that you'll have chains of side effecting futures like readFromDb() .flatMap(x => doSomethingElse(x)) .flatMap(x => doSomethingElseAgain(x)) .flatMap(x => onceAgain(x)) And this all gets passed up the call stack to one generic thing that basically does nothing in the case of error, maybe logging it and that's it. It…
Re: From First Principles: Why Scala?
#304Earlier quoted context omitted.
This is spot on! Way too often in Scala codebases, which tend to wrap IO calls in Future or similar is that you'll have chains of side effecting futures like readFromDb() .flatMap(x => doSomethingElse(x)) .flatMap(x => doSomethingElseAgain(x)) .flatMap(x => onceAgain(x)) And this all gets passed up the call stack to one generic thing that basically does nothing in the case of error, maybe logging it and that's it. It…
I dunno. You see the same pattern with chained class methods in Python and it suffers from the same exception specificity problems, but doing it is still a fair judgment call. Sometimes all you need to know is that there was an error in the chain. Like if an exception is raised by dataframe.transpose().to_dict().values() I don’t ask myself where in the chain the error occurred, I just think, “oh that’s weird why coul…
Re: From First Principles: Why Scala?
#305Earlier quoted context omitted.
How is concurrency implemented in Scala.js? Eg switching tasks when you use Future for concurrent long running tasks that do IO or sleep?
Scala's Futures work unchanged, it just has a single-threaded threadpool instead of a multithreaded one. Anything built on Futures (e.g. my Castor actor library) is unchanged as well. Scala Futures are more or less a 1:1 mapping to Javascript Promises, and work identically. There isn't long running IO or sleeps, same JS, but this isn't a big problem in practice. As long as you're not juggling threads directly - and m…
I think in this case Clojure provides pretty strong competition with core.async - you do have to use the async specific calls for sleeping and channel IO but it still works using the same API on JVM Clojure and ClojureScript sides.
Re: From First Principles: Why Scala?
#306Earlier quoted context omitted.
I am fairly certain the jury is out on this question: It's always better to write simple, almost dumb code that anyone can understand than to use advanced abstractions from category theory or whatever. Why? Because every single study or anedocte I've ever heard is like yours: adding complex abstractions to code do NOT make it more reliable. But they do make it much harder to modify, understand, and fix. FP tought us…
Finding the right level of abstraction is basically the one and only skill that matters for a software engineer IMO. I've got about 15 years of experience in programming and it's still something I'm actively working on. I disagree with the general take that "adding complex abstractions to code do NOT make it more reliable". Good use of abstraction makes code easier to write, easier to maintain and easier to extend. G…
This is the reason I used the term "overly complex abstractions", not just "abstractions" in general, of course. Overly complex meaning it's a failure to use "the right abstraction" where you instead go for something much more complex than the proble called for... this is what I understand most people in this thread are referring to when they refer to previous Scala projects they've worked on.
Re: From First Principles: Why Scala?
#307Earlier quoted context omitted.
The JVM offers real threads, and JS not. The JVM offers nanosecond-precision time measurement, and JS not. JS has a single type for representing numbers. And so on. How can those possibly be abstracted away and unified? If doing so, what would have the solution have to do with type inference at all? i.e., this is simply a difference in how one approaches platform interop (raw vs abstracted/unified). Clojure occasiona…
> The JVM offers real threads, and JS not. How does this make a difference to the Clojure interface to threads? After all, if you're running your JVM on hardware that doesn't support parallelism, you're not getting parallelism anyway. > JS has a single type for representing numbers. The comment you're replying to already covered that: > For example, the reason Scala.js can provide exact semantics for numerics while m…
Clojure futures, promises, and some of its other concurrency primitives have synchronous semantics. So they don't take callbacks, instead the calling thread blocks on the result when it's at the point where it needs to wait for it.
So that interface doesn't work with JavaScript's concurrency model. On the other hand, Scala futures have a asynchronous interface, and you specify a callback for success and error, and cannot block waiting for them, which happen to be 1:1 with the JavaScript promise interface.
That's why on ClojureScript you don't have access to those concurrency construct, since they just don't work within the JavaScript model.
The compiler maybe could have gone through amazing lengths to rewrite all use to an async one, but it just so happens there is already in Clojure something that does so, but it rewrites a CSP interface to an async concurrent model (not futures and promises). It's called core.async and this one exist in both Clojure and ClojureScript.
> I can understand providing different libraries for different platforms, but language semantics should remain (as much as is possible), e.g. numerics
Even Scala.js has some differences in numeric types they list in their page. There's always the possibility of mismatch of a language over some runtime. In ClojureScript I think it was planned to eventually bring the same numeric semantics over, but they started without, and it seems no one minded and then never bothered.
Re: From First Principles: Why Scala?
#308I dabbled with Scala several years ago, but I've been using Kotlin for a JVM-based project and am happy with it. My main reason for choosing Kotlin is smoother interop with the JVM world. For example: - Scala adds an Option type, whereas Kotlin adds nullability checking for existing object types. - Scala has its own convention for getters and setters, whereas Kotlin automatically turns JVM getters and setters into pr…
Scala is positioned to write new code while using old java libs
Kotlin is positioned to write code/libs which can be shared with new java code
The theme is replacement vs co-existing!
Re: From First Principles: Why Scala?
#309The author argues that dynamic languages like (JavaScript, Python) have Poor IDE and Tooling Support and are Unmanageable in large programs. I'll counter that if you add a type checker to one of these languages, such as TypeScript (for JavaScript) or mypy (for Python), then all of those problems go away. I'm personally particularly excited about the possibilities unlocked in the Python community by type checking, whi…
Then, creating a good typesystem is really really hard. Even professional language designers struggle with that. Take Martin Odersky, the creater of Scala. He didn't just invent Scala, no, he learnt under his professor, then created pizza-lang and did other experiments and worked with other languages (e.g. he was the one who added generics to Java) before he used all his expertise to create Scala. And even then mistakes were made.
You can see it from the language. I work with both Scala and python (with type annotations) and you can see that one is created by a specialized professional, where the other one is created by smart people but not with the same sophistication.
> Additionally, RE "Poor performance" the author is presumably talking about CPU-bound performance.
He probably does, but these languages are most often also better for IO-bound programs. The reason is that writing asynchronous and concurrently executed code is very difficult and pretty much adds another layer of problems on top of everything someone does. Languages with static types (not only Scala) can leverage a big advantage here, because the compiler can help you to indicate what is synchronous and what isn't.
Re: From First Principles: Why Scala?
#310Earlier quoted context omitted.
Yes, it is a side-effect - and does make the code impure; but it's an /exceptional/ flow like OOM, infinite looping, stack overflows which also break equational reasoning. My argument is that as a programmer you /choose/ the base lemmas which you're comfortable with - with an exception you're saying for a large swathe of your code, it will assume a lemma. When is /does/ break you get to point the finger at it with a…
This is spot on! Way too often in Scala codebases, which tend to wrap IO calls in Future or similar is that you'll have chains of side effecting futures like readFromDb() .flatMap(x => doSomethingElse(x)) .flatMap(x => doSomethingElseAgain(x)) .flatMap(x => onceAgain(x)) And this all gets passed up the call stack to one generic thing that basically does nothing in the case of error, maybe logging it and that's it. It…
try {
doSomethingElse(x)
doSomethingElseAgain(x)
onceAgain(x)
} catch {
...
}
where each method just returns Unit or throws exception? The version with IO/Future is superior since it at least explicitly states that you can get an error here. If you want to say that Go-style error handling is better because if forces errors handling, I can kind of buy it, but it also has some cost.>You don't have while/if-else/etc
Maybe you are looking for ifM/whileM functions from e.g. here: typelevel.org/cats/api/cats/Monad.html.