zenhack
At some point the project would greatly benefit from some attention from a UI/UX specialist -- I'm doing my best, but it's not what I'm an expert at. Though right now I'm mostly focused on getting enough stuff to work for it to be of interest, and someone fussing with the UI might just be distracting.
Doing app packaging for Sandstorm might be the most accessible way to help for someone who's not a Go dev -- Tempest will of course benefit from more apps when it's ready to run them, and it'd be a high impact thing for the community right now.
I don't think app packaging could be said to be the achilles heel -- how much work it involves depends a lot on the app (some things are very easy, others can be painful), but it is certainly not the case that Sandstorm didn't take off because packaging was too hard.
But yeah, Sandstorm has been in a state of "not dead but not moving fast" basically since the company went under; things picked up a bit in 2020, and I got oriented-enough on the codebase during that time to keep it floating along, but, per the post, it's never been easy going.
Anyway, I wish I were answering this question in 6 months time, when I'll be able to show off a variation of Tempest that is relatively usable and can do a few tricks that Sandstorm can't.
The ergonomics of the Haskell implementation could use some work IMO, and I've got some ongoing refactoring work on a branch. But it does work, and folks are using it.
[1]: http://erights.org/
What situations do you run into where array indexing is not an acceptable substitute for pointer arithmetic?
I've been working off and on on a language that tries to get the best of both worlds to some extent. The whole language is built around making sandboxing code natural and composable. Like Rust, it has a macro system, so lots of compile time logic is possible without adding complexity to the build system, but macros don't have access to anything but the AST you give them, so they are safe to execute. There's a built in embed keyword that works like Rust's include_bytes, which runs before macro expansion, which you can use to feed the contents external files to macros for processing. At some point I'll probably add a variant that lets you pass whole directory trees.
What there is instead is an expectation of how much work you're supposed to get done per unit time (albeit calendar time in shops that have things more together). But this is in turn informed by how much time you are expected to devote to work vs other parts of your life.
(Given your numbers and the ones in the talk, it would appear medium pages have doubled in size since the talk was given).
But yeah, I think folks reach for heavyweight frameworks too quickly. You shouldn't be using React for a blog.
- capnproto/capnproto
- sandstorm-io/sandstorm
- erlang/otp
(I don't remember the order).
I actively contribute heavily to sandstorm. I've sent patches here and there to capnproto, and it's vaguely a sister project to sandstorm. Those are probably some of the most popular projects I have multiple contributions to, though there are others.
otp feels a bit odd though, if there's and "and more" -- I sent them a one line patch to fix a build error when building against musl. I haven't really been involved since, nor was I before. But it's a high profile project.
1. Packages tend to be smaller, and the transitive dependency trees of projects corresponding larger. This means there are more single points of failure.
2. More people are using it.
Python, and for that matter most language package ecosystems, have the same problems as js, but many of them have gotten away with it for a bit longer due to (lack of) scale.
I wrote the Haskell implementation. It maps unions to variants (what Rust calls enums), BUT it always generates an extra 'unkown' variant, which gets used whenever the variant is one not recognized by the generated code.
In this case the value proposition of variants/enums, including exhaustiveness checking, is still really useful -- it can not only deal with the possibility of more variants added in the future, it forces you to handle that possibility, which imo is the best of both worlds.
But yes, in general, when modeling data that comes from the outside world, you need to about overfitting.
Vaguely related: https://lexi-lambda.github.io/blog/2020/01/19/no-dynamic-typ...
- There are a bunch of references to other folks using the term, all of which are big names I recognize as being pioneers in open source consistent with the OSI's notion of it.
- The mailing list posts enumerate a bunch of advantages that would not follow from mere availability of source code without additional rights consistent with the OSI's general notion.
The sense I get from this is that the term probably was in use already, but it pretty much meant what the OSI says it does, not just "the source is out there."
But I think most folks have in mind something more permissive than just being able to /view/ the source. In particular, being able to modify, run, and redistribute are also essential (the fsf's four freedoms get closer to the heart of the matter).
I think "you can't use it to do X" disqualifies the license, though in this case I'm not sure how much I care, since it's prohibiting things that are illegal where I am anyway (maybe if your country doesn't have a dmca equivalent it might matter).
https://hackage.haskell.org/package/dynamic
Which is an entirely different package, and the relevant types are entirely different. Only the name is the same. The `dynamic` package does indeed appear to be an april fools joke.
The Dynamic type in base is about runtime reflection, which is occasionally useful but not something that comes up often and not really about rapid prototyping.
1. C++ templates don't require you to treat the type variables as opaque; depending on what the body of a template does with its type parameters it may or may not type check depending on how the variable is instantiated. By contrast, in OCaml (and most languages) generic functions cannot assume anything about their type parameter. This means that the compiler can type check the body of the generic function once and be done, rather than having to essentially check it at every call site.
2. Aside from type checking, C++ templates generate separate code for each instantiation of the type parameters. This (generally) results in faster code as it is specialized to the type in question, but it means more code is generated, which of course takes time (and it can also bloat the executables). This is probably a bigger deal than the type checking part. By contrast, OCaml only generates one copy of the code for a function, which simply doesn't care about the types of its arguments. This is also a common implementation strategy; Java does something similar.
Note that Rust also suffers from (2), but not (1).
http://stedolan.net/research/mlsub.pdf
So this can be done, though afaik there's still some theory work to be done to combine it with some of the more advanced features in modern FP languages (e.g. higher rank types)
Also "stuff like" is kind of the problem; all of the smart pointer types have differences that matter, and none of them is general enough to cover all use cases. Arc<Mutex<Box<T>>> comes the closest to a "general" solution, but the boilerplate is rather a lot just for the sake of not having to think about this stuff, and you still can't use it if T isn't Send.
You're really picking a fight with the language if you insist on avoiding making these decisions, and in the end it will just slow you down even more than going with the grain. And to add insult to injury, if you write all your code like that it'll likely be slower than OCaml or Haskell anyway. Rust can't keep up with a good GC on allocation throughput; the performance advantages come from managing things yourself (and avoiding heavy allocation in the first place).
Rc and friends are useful, but they don't make the problem go away.
As I said, it's not that it's even really all that hard. But it is time consuming.
This isn't a criticism of Rust; it's specifically designed for applications where those things do matter. But for the overwhelming majority of apps they don't, and I'd reach for a different tool.
I've found that once I get into a rhythm and I've been working on something in Rust for a bit, it doesn't feel that hard to deal with all that. And a few times I've thought to myself "hey maybe the GC isn't actually buying you all that much?" But then I go back to a GC'd language and watch just how much faster stuff gets done. It's not even close. I think it's one of these things where your brain doesn't notice the time that goes by when you're doing what is essentially mindless busywork.
Part of this is also having come from doing a fair bit of stuff in Haskell, Elm, and a bit of OCaml; the best "high-level" language features are inspired by that language family (including enums) and so it feels like a better control for the difference a GC makes vs. js and friends. It makes a big difference.
LLVM as a toolchain provides backends for many target machines, so as a compiler author you can just emit LLVM IR and (mostly)automatically be able to compile for x86, arm, mips, etc... And they have a wasm backend too, so the technologies are complementary -- you can use LLVM to compile to wasm. LLVM will do a fair bit of optimization too. The intent with LLVM is not to provide a portable binary distribution format, but to allow different compiler frontends to all share the same compiler backend logic.
By contrast, with WASM the assumption is that by the time it gets to the browser the ahead-of-time compiler has already done a fair bit of optimization, so what a wasm compiler has to do is much simpler.
WASM is also designed for space efficiency, since the code will be shipped over the network, and safety -- LLVM has a C-like notion of undefined behavior (which the optimizer makes use of), but this would be wildly inappropriate for WASM due to security (and portability) concerns.