684 karma · joined June 20, 2017
If at all; probably obvious, but important to point out that in a startup environment this kind of mistake could just outright kill the company.
I work on an open source project (Sandstorm[1]) that was started by a now-defunct startup. There's a repo that's unmaintained at this point (It might still work?) containing a high-scalability backend that had been used to manage Sandstorm Inc's hosted offering. Apparently they never got to the scale where they couldn't have thrown one giant server at it and been fine, and it pulled a lot of resources away from other (ultimately more important) development tasks.
...and now I'm stuck developing against mongo for no good reason :P
[1]: https://sandstorm.io
Both languages suffer from patchwork build infrastructure; interpreted languages are great when you have one file and no dependencies, but as soon as you grow a bit beyond that rules about where to find modules make things complicated. Both languages have developed tooling around this that suffers from being an afterthought, and I'm not sure which is worse.
Fwiw, I've been using arch as my daily driver continuously for 14 years and haven't ever really felt the strong need for an AUR helper.
...and the rest of the states...
But it's a one-time fee, so you're probably still right in general, but for the moment I'm mostly coasting on savings & sponsorships, focusing on the stuff I care about while I have the breathing room. I might consider being a bit more organized if/when I ramp up business again and am considering looking for new clients.
It's so much easier in the US. If you're an individual it's going to be taxable income, but there's no up-front paperwork to do (for that matter, you don't have to "set up" a sole proprietorship here either -- that's just what the tax code calls "some rando doing business by themself"). I've done contract work for years, have a bit of my income coming in through GitHub sponsors now.
Now, if we could only get health care covered for folks who don't have an employer...
---
> I host a free project myself and I've had to set up a business (sole proprietorship) and sell things in order to get money for server costs.
What's your side project? Speaking of Sandstorm, I'm wondering if it might be relevant; dealing with the problem of developers needing to monetize things in order to cover hosting costs was one of the motivations for the project:
https://sandstorm.io/news/2014-07-21-open-source-web-apps-re...
It does seem like Rust is just enforcing the rough consensus in the Haskell community re: best practices.
But more than "how are we doing vs Apple and Microsoft?" I'd kinda prefer to set the bar a bit higher. Desktop operating systems (all of them, at least with actual users) are just completely architecturally backwards for the reality of our modern security landscape, and what users need from their system. Protection boundaries are still mostly between different users. for most systems that's borderline useless, as there's only one user. Meanwhile every app runs with the full authority of the user and can do anything they can do.
Smartphones are a little better; Android equates "user" with "app" which is at least vaguely useful. But the permissions you end up with are still too coarse grained.
There are better designs out there. For example: web pages can ask the user for a file without getting access to everything the user owns (or at least in the case of Android, all of their files). Why can't native apps do this?
The Template Haskell paper has some interesting things to say on the nature of C++ templates:
https://www.microsoft.com/en-us/research/wp-content/uploads/...
- It gets you really garbage error messages, because the type errors are usually about something in the body of the template, wherever it tries to do something that the type you substituted doesn't support, rather at the offending call site.
- It hurts compile times (above and beyond proper generics), since you need to type check the generic function at every call site, rather than just once.
- It makes it easy to break interfaces, because exactly what is required of a type parameter isn't written down anywhere -- it's just whatever the body tries to do with it.
(Though it is also true that generics are certainly not a full substitute for macros. I would welcome some mechanism for doing codegen that didn't complicate the build system and was a bit lighter weight than what we have now).
But dyn impl is a trait wrapped in an existential. There's no concrete type a -> b, only a trait for types that can be 'called.' So to pass an arbitrary function around in a record/struct you need to do the very thing the post is saying is an antipattern (in Haskell). So the argument doesn't really apply to Rust because there isn't a simpler more direct way to achieve the same thing.
Also, there's a lot of disagreement about exactly what the distinctions between `lambda`, `closure`, `anonymous function` and friends mean. The interpretation of `closure` I'm interested in is basically a bundle of code and data, which can be treated abstractly in a first class way. That could be something that appears as a lambda capturing variables in the text of your program or as an object in a more OO setting which, albeit more verbose for a single function, has a similar level of power of abstraction.
Either way, part of that power is being able to write code that can work with the interface (irrespective of the shape of the enclosed data), and do things like store differing implementations in lists/vecs etc. The only mechanism Rust provides to do that is trait objects.
Higher rank types also break this, as you can define things like:
newtype GenericThing = GenericThing (forall a. [a] -> a)
doManyGenericThings :: [GenericThing] -> [a] -> [a]
doManyGenericThings things list = map (\GenericThing f -> f list) things
Here, `doManyGenericThings` takes a list of generic functions, and applies each of them to its argument. You can't just monomorphize it, because you'd have to somehow also monomorphize every argument it is ever passed, which is a dynamic property that you can't know in advance (and again, may not be a finite set).
struct EventHandler { handle_start_event: fn(), handle_completion_event: fn(), }
...but this differs in a key way from the haskell example: Rust's `fn` is not a closure, it's just a pointer to some code, and you can't construct them dynamically. If you want to pass around a _closure_, you need ...a trait object.
Something like:
struct EventHandler { handle_start_event: Box<dyn impl Fn()>, handle_start_event: Box<dyn impl Fn()>, }
...but that's exactly the pattern the author of that post is suggesting getting away from.
I agree with the author's point, but it doesn't really apply to Rust because there isn't actually a simpler way to do it. And I think that's part of what the OP was getting at -- Trait objects are the closest thing Rust has to proper closures, and they're a bit awkward.
Note that I'm still something of a newbie at Rust, and don't feel like I can really say much about the day to day experience of using (or avoiding) trait objects due to limited experience.
...not that I've ever had anything useful come from talking to a recruiter. The useful bits have always come through my existing personal network more directly, or through meatspace networking. I shut down my LinkedIn because I basically started to view recruiter emails as spam.
Up until now the bar has been far lower than that.
Wasm is a good example of a bytecode format designed for small code size. Though I expect wasm may often still be larger than equivalent js just because it's so much lower level. But there's no reason you couldn't design a compact bytecode format with high level semantics, and I would expect it to beat any human readable format.
> Perhaps if ES4 landed, fewer people would need complex build tools like Babel, Webpack and Typescript.
I'd pose it the other way: if stuff like Babel existed at the time, folks might have actually written es4 because they could do so without breaking backwards compatibility. And most of the value in a static type system is the ability to flag errors before running the program, so I don't think there's anything you can add to the browser that would have obviated an offline tool for that.
Frankly, I think we'd be better off if we started getting a lot more selective about what gets added to browsers. Adding more and more features to browser's js implementations is silly when most folks are using ahead of time build steps to get access to those features without the browser's help. And continuing to add things is a great way to ensure that they'll keep right on using those tools, so they don't have to worry (as much) about who supports what. And it just makes the barrier of entry for building browsers higher and higher.
There's more utility when native browser support can do something a compiler can't. Things like reducing code size for really widely used functionality, enabling technologies that can't be bootsraped through developer tools (e.g. WebRTC). I'd like to see additional growth of the web platform be focused on areas that can't adequately be addressed by separate tools.
(Maybe you were familiar). The closing is particularly worth taking in:
> Finally, don't be surprised. The current model of total surveillance and permanent storage is not tenable.
> If we keep it up, we'll have our own version of Three Mile Island, some widely-publicized failure that galvanizes popular opinion against the technology.
> At that point people who are angry, mistrustful, and may not understand a thing about computers will regulate your industry into the ground. You'll be left like those poor saps who work in the nuclear plants, who have to fill out a form in triplicate anytime they want to sharpen a pencil.
> You don't want that. Even I don't want that.
> We can have that radiant future but it will require self-control, circumspection, and much more concern for safety that we've been willing to show.
> It's time for us all to take a deep breath and pull off those radium underpants.
I'm not sure it came in the form of a single event (though I can think of some candidates -- the cambridge analytica scandal made a big impression for one), but it's clear to me at this point that the warning was ignored, and our industry has missed the window for self-regulation.
Algorithms designed for password hashing are intentionally both compute and memory intensive, to make guessing slower, whereas general cryptographic hash functions are by contrast intended to be fast, as most applications will want that. The idea is that password hashing algorithms should be fast enough to keep up with a human and no faster; if you already know he password the performance is not a hindrance but if you have to guess it makes doing so impractical.
Firefox on Linux.