2,890 karma · joined June 30, 2015
Static types are a form of static analysis. One that is deeply integrated into the language and compiler, which gives obvious advantages such as machine-checked documentation, custom invariants and error messages (expected a Currency but got a Country), better code generation, better tooling (IDE pop-ups, fast incremental checking) etc. Other forms of static analysis are of course useful too.
IMHO, programming in Rust is no harder than C++ or C. It just forces one to be explicit about lifetimes and ownership, concepts one should be carefully thinking about in other systems programming languages.
In your example, why bother naming the inner "x" variable for the function param? It cannot be used on the right-hand-side (definition of "bar"). For that reason, the notation is not exactly "clear". In OCaml the annotation would be:
bar( x : int -> string )
But foo(x : int) is a string! It literally reads "foo applied to x". In the function definition, it appears to be used as a left-hand-side pattern which is "matched". The definition is written as if to say, whenever the term foo(x) is encountered, use this definition here. At least, that was my expectation.
> Haskell doesn't use that notation either
OCaml does and Haskell once had a proposal to add it. Haskell type signatures are normally written separately, but it does support annotating patterns with the right extensions.
foo(x : int)
Therefore, one would expect to annotate the return type as,
foo(x : int) : string
Since the pattern is showing foo applied to x. The Rust syntax is actually confusing for both Haskell/ML programmers (where the arrow comes from) and mainstream programmers. It's too small an issue to change now though.
Rust's support for proper "algebraic data types" is very good and gives it an advantage over languages like C++. However there are some small surprises, such as forcing all enum constructors/fields to be public (one must therefore wrap it to make an abstract data type).
Every language has its warts and these are particularly minor ones.
Monads can be used to implement "effect types" and define the semantics of them. I believe this is how Koka works.
> Talking about Haskell monads just does not seem all that relevant in this context.
I respectfully disagree. Async/Await first appeared in F# as a Monad (Computational Workflow). Monads also do not necessarily have to involve closures at runtime, they can be useful just to define semantics and build type-checkers.
While Go's model is certainly a valid point in the design space and keeps things nice and simple, there are of course going to be many trade-offs. For example, low-level control is very much lost. There are no opportunities for custom schedulers, optimising how non-blocking calls are made, or easily dealing with blocking syscalls (or foreign libraries that call them). It would not be the right approach for Rust.
Microsoft's Koka is an example of a language that further empraces effect types and makes them easier to use: https://koka-lang.github.io/koka/doc/index.html
This is completely wrong. For example, a Lenovo X1 Carbon is 2.5 pounds, which is lighter than a MacBook Air at 2.8 pounds. It also offers 32GB of ram, does not have a glued-in battery, does not use glass and the keyboard is much less likely to fail. I am tempted by the M1, but from my experience Apple machines are heavier, fragile, less reliable and less user-serviceable. I also don't understand the aversion to plastics. Aluminium makes MacBooks heavy and can attenuate radio signals.
The sad fact is that there is simply no money in building email clients. Email is a legacy technology and arguably no longer fit for purpose. We need a new standard and that's not something that BigTech has delivered yet.
Thunderbird is pretty good and in my experience, less buggy than Apple Mail, especially when using providers other than iCloud. My wife absolutely hated Apple Mail, primarily because it would forget passwords and stop syncing/sending. So I moved her to Thunderbird and now she's happy.