I think it's great that some people don't care about the technology behind their blog and instead focus on writing, but this is taking the cake. I keep accidentally editing this blog post as I am reading it and there seems to be no easy way to stop it from happening...
edit: Oh my god, this is your product!? Please, this is a stupid gimmick. Middle click on X11 pastes the selection buffer, a critical feature for my productivity, and now when I try to open links in a new tab I end up pasting text I've selected.
wonrax · 1d ago
I thought this was a gimmick too until I went to their landing page and it's also an editable doc. It's intentional.
bmacho · 1d ago
> Oh my god, this is your product!? Please, this is a stupid gimmick. Middle click on X11 pastes the selection buffer, a critical feature for my productivity, and now when I try to open links in a new tab I end up pasting text I've selected.
Indeed, there should be a non-editable mode.
tasuki · 9h ago
Make it a paid feature and you'll be rich beyond imagination!
Joeboy · 1d ago
It's slightly more forgivable because at least the text is supposed to be editable, but Azure tickets also have this middle-click issue. It's infuriating.
weinzierl · 1d ago
That is a very positive article and it matches my experience, the only bleak outlook is:
"async has a relatively high complexity cost for us due to the 'static bound (cc), cancellation-safety, and restrictions relating to traits and dyn. These currently seem insoluble. Bifurcation between sync and async primitives and ecosystem idiosyncrasies further increase the async tax. Effects-inspired solutions seem unpromising."
"Pre-1.0 Rust had a solution: libgreen. It achieved concurrency in user-space without this bifurcation, but at significant performance, portability and maintenance cost and so was removed. With increased engineering bandwidth this may be worth revisiting. Again the language simplicity would be worth it. (One day I’ll create a PoC of zero-cost wrapping of std::{fs, net} plus fiber::{spawn, select} using generator!)"
davidhyde · 1d ago
> “async has a relatively high complexity cost for us due to the 'static bound (cc)”
I stand to be corrected but I believe that this is design choice of the Tokio async runtime and not a Rust design choice. For example, the Embassy async runtime does not have this bound but then you have to handle pinning yourself. Also, the static bound is supposed to lower the complexity cost, not raise it.
vascocosta · 1d ago
As someone who dove deep into Rust at the end of 2022, I always find it interesting to read these stories from people who went through the harder times it was back in 2015. I feel lucky to have learnt the language when it was much more developed, as it certainly made the already steep learning curve a bit more comfortable.
In a way I feel like I'm going through what is described in the article but for Zig. I guess Zig is more or less in a similar place now to where Rust was back then. Still I enjoy very much using it already.
estebank · 1d ago
There's a strong culture of "leave things better than you found them". When a user gets confused by the tooling/language, it's not the user's fault. If you got confused, chances are that others will too, so fixing/improving things when we encounter them has unbounded benefit. Second best time to plant a tree being today and all that.
One benefit of this is that if someone tries and bounces, when they try again a year later their experience might be improved enough that they don't bounce again. For a while I was of the thought that the best piece of advice I could give someone wanting to learn Rust was "wait 6 months" :)
jvanderbot · 1d ago
This is such a great attitude. I know LLMs are becoming the new Godwin's law, but I really wish this attitude was pervasive in LLM-based tooling. "If it's not working you're prompting wrong" is all we have. But I guess "wait 6 months" still applies (except then you're "NGMI").
vascocosta · 1d ago
I very much agree with this and that's one of the reasons I keep using Zig as it is now. I try to provide feedback on what isn't very obvious to me.
tonyhart7 · 1d ago
whenever programming language adopted into big tech (MSFT,Google etc) or Big OSS (Linux etc) is already prove its mature ecosystem
but I cant say the same to Zig because I dont see it as (big) update compared to what we have
vascocosta · 1d ago
For me the value in Zig is its simplicity as a language (in a way similar to go's simplicity) and the explicit and very fine grained control over memory allocation. On top of that, I really appreciate tagged unions and error handling. It adds enough value on top of something like C to make it worth for me.
Still wherever I need absolute code correctness and production grade quality, I use Rust, my favourite language, at the expense of more code and spending more time doing it "the right way".
metaltyphoon · 1d ago
> value in Zig is its simplicity
IMO, there are things Zig just don’t care about, which in the surface makes it simple but its annoying and burdensome later on.
* Manual interface implementation
* Internals of a struct is public
* No string types
* anytype requires reading code
* Error can’t carry information
* The iteration abstraction in the std is all over the place
* Unused declarations is compilation error
vascocosta · 1d ago
I resonate with you about interfaces and a String type. At least these two are so prevalent even on the simplest of programs to warrant some proper language and std lib support.
throwawaymaths · 1d ago
> For me the value in Zig is its simplicity as a language
I was reading an article about rust posted here yesterday and i realized: i have no clue what is going on in this code (also i presume "templage" is a typo):
Looks like a small request handler for an HTTP framework using a page written with the jinja templating engine. I'm a bit rusty (pun intended) so I can't immediately place which HTTP framework that is though.
dsff3f3f3f · 1d ago
You're correct and the HTTP framework looks like Axum.
throwawaymaths · 1d ago
i mean i got that part :). my best guess is that the async function is some sort of factory? why you would need a factory to be async i have no idea.
vascocosta · 1d ago
Yes, while macros simplify some tasks, they also make it harder to really understand the code. Well, technically they hide the code in most languages as they're metaprogramming done in a separate language.
I love Rust and do some advanced code sometimes, but very rarely have I created a macro. I still see it more or less like "magic" that "super-human" library developers master to make their life easier. Typically not my use case.
This is another advantage of Zig. As you may know, metaprogramming in Zig doesn't use any special syntax, but rather the Zig language itself. This is often known as comptime and while not necessarily easy to grasp, as you're reasoning about compile time stuff, at least it's done in pure Zig.
throwawaymaths · 1d ago
to be fair you can generate a type in zig using a function that results in kinda obscure methods etc. i do think zig devs shy away from that kind of patterm though.
Narew · 1d ago
I personally think that the discovery of rust API is awfully as soon as macro is involve. It's impossible to know what argument is taken by macro.
For example the "simple" `println!`, without example in the docstring it's impossible to guess what are the argument even when we have an IDE that show you the implementation.
cogogo · 1d ago
I know nothing about zig so just looked it up on wikipedia. Apropos of nothing it’s the first wikipedia article I’ve read that I’m convinced was written by/using an LLM.
Having skimmed it, I had the opposite reaction, the wording is clunky in a way that I haven't seen LLMs do, it feels very human to me.
Stuff like
> Also the learning curve for Zig can be steep, especially for those unfamiliar with low-level programming concepts.
I don't think an LLM would start a sentence with "also" like that
> The small and simple syntax is an important part of the maintenance, as it is a goal of the language to allow maintainers to debug the code without having to learn the intricacies of a language they might not be familiar with.
The wording here feels like someone who's a fan of Zig taking a sentence praising Zig's design and trying to rework it into a slightly more neutral encyclopedia style.
zesterer · 1d ago
Accidentally clicking on anything resulting in accidental local deletions and modifications to the article is extremely irksome. Skill issue, I guess?
smokel · 1d ago
Took me a while to figure out what you meant, but apparently this blog post is hosted on Tably [1], which allows one to edit the page locally. One would expect there to be a setting to disable these features for a public post.
Noted, and working on it! Pages are copy-on-write as most on the site are intended to be templates where that behaviour makes sense. Working on mitigating annoyances like those observed in these threads. Longstanding browser-specific issues like https://bugzilla.mozilla.org/show_bug.cgi?id=1001790 make this tricky!
bmacho · 1d ago
Nah, it's needlessly hostile (just look at the comments).
> Longstanding browser-specific issues .. make this tricky!
I don't think it's true, there are no browser-specific issues that stand in the way of anything that people are complaining about. Or do you have a PoC in whatever browser?
lmm · 1d ago
Can you make those funny buttons that you're using to refer to other websites look less like links? It's pretty confusing when I see a blue word that underlines when I hover on it but I can't middle-click it.
MarkSweep · 1d ago
Does a blog post really need to be contenteditable? The vast majority of people viewing the page are only going to viewing the post, not editing it.
SSLy · 1d ago
btw, can you make links be `<a>`?
strken · 1d ago
The irritating thing for me is that their links have somehow broken the middle mouse button, so each time I want to click on one I have a few seconds of trying to remember how their specific site implemented it.
veltas · 1d ago
This to teach a lesson about the perils of unnecessary mutability.
syndeo · 1d ago
Well, I used the power for good and put a crab emoji at the end haha
noelwelsh · 1d ago
I deleted a paragraph from the post. That was unexpected. Nobody really cares about large types though, right?
I suppose if I find anything I really disagree with I can correct it, so that's a bonus.
bravesoul2 · 1d ago
I rewrote it to be about Go
ninetyninenine · 1d ago
I feel rust promotes functional programming. I created a parser that would change its own state on an advance but the mutability and borrowing kind of made it hard to do it that way so I changed it so that the parser was stateless and had to return an index rather then adjust an internal index. Is it common for people to hit issues like this where the traditional pattern just doesn’t work and you have to do it a completely different way for rust?
vascocosta · 1d ago
I've experienced this. I would say it depends a lot on the complexity at hand, so for instance if it's something rather simple, you can keep track and avoid pitfalls even when doing it with a lot of mutation and imperative style. On the other hand, when complexity grows, I find myself going more functional and avoiding mutation at all cost, as obviously it avoids a lot of problems.
I would say Rust's borrow checker and lifetimes make it harder to use traditional patterns and favor a more functional approach. Obviously, sometimes doing it the functional way might be hard, for people not so used to it, but it keeps the compiler happier I would say.
theThree · 1d ago
Async/await is the only thing prevent me from using Rust.
jvanderbot · 1d ago
It should be one of the main things bringing you to Rust, because it simplifies a lot of typical concurrency patterns.
When I started out, it felt icky and like some kind of infection that everything eventually had to be async, but that was because I didn't understand how to interact with async code. Using spawn, spawn_blocking, and futures::stream is 90% of my use case, and it makes it easy to set up "barriers" beyond which async doesn't need to spread.
mrkeen · 1d ago
I did a fair bit of Rust (only single-threaded, quite a few years ago) but it sounds like the dependency inversion principle is popping up again.
DIP, async/await, coloured-functions, io-monad. All cases where the business logic should go in one column (abstract/sync/blue/pure), and your machinery should go in the other column (concrete/async/red/io). Your logic will remain unit-testable that way, regardless of how big or small it gets.
Irritated newcomers will complain about not being able to call in the other direction. So what's a language-designer to do? Attract the largest possible user-base by not getting in the user's way - or filter out frustrated users and have fewer but better codebases out there?
jvanderbot · 1d ago
Dependency inversion does apply sometimes, but a well-designed library caps async around functions that need it - things that interact with filesystem or network, etc. Those are perfectly testable as-is. Your core business logic is still sync, if you'd like to to be. Async can call sync just fine, and sync can call async, as long as you are willing to admit that you're abstracting away a network call in a unit tests (for some reason).
The typical pattern I enjoy is:
* Sync for the logic
* Async for the job runners b/c I'd like to do other things while it's going.
* Sync or Async as required for the data wrangling (db calls, network, filesystem)
So you have essentially:
1. kick off job, returning a future, by calling an async function.
2. Job is mostly async data wrangling, followed by a sync logic block that's unit tested, followed by an async "save" if required.
3. Either wait for the future, or run the task in the background, or `.await` if you're in an async block.
I'm hand waving away the syntax, but that's the mental model. 99% of code isn't async, and the code that is isn't async for the fun of it.
vascocosta · 1d ago
I know where you're coming from. But for me it's one of the main reasons I use Rust, since it clicked for me after the initial hurdles. Contrary to the average opinion on this, I like the syntax and don't mind so much about function colouring.
Especially when using tokio I feel like my solutions work out pretty well. I also very much appreciate how they create async equivalent functions for pretty much any std function worth using. Maybe this creates a divide, but my concurrent programs feel easy to code and the performance is pretty good.
My only semi-issues are probably stuff like task cancellation, however I attribute that to skill issues on my end, rather than tokio or the way async/await is implemented in Rust.
pjc50 · 1d ago
Doesn't it have it now?
vascocosta · 1d ago
It has and it's both pretty mature and extensively used. Some users have philosophical reasons against using async/await at all, so I believe that's why the user said that... The other option being the user doesn't like the way it is implemented, compared to other languages.
blacklion · 1d ago
1. This site shows links in such way, that browser doesn't show target of the link in the bottom of the window
2. I've tried to re-use tab bu typing new URL into URL bar and it doesn't work, browser re-open same page and replace URL back!
WTF?!
IshKebab · 1d ago
Middle click doesn't work on your links btw. Oh... wait this is like some live editing view? What?
edit: Oh my god, this is your product!? Please, this is a stupid gimmick. Middle click on X11 pastes the selection buffer, a critical feature for my productivity, and now when I try to open links in a new tab I end up pasting text I've selected.
Indeed, there should be a non-editable mode.
"async has a relatively high complexity cost for us due to the 'static bound (cc), cancellation-safety, and restrictions relating to traits and dyn. These currently seem insoluble. Bifurcation between sync and async primitives and ecosystem idiosyncrasies further increase the async tax. Effects-inspired solutions seem unpromising."
"Pre-1.0 Rust had a solution: libgreen. It achieved concurrency in user-space without this bifurcation, but at significant performance, portability and maintenance cost and so was removed. With increased engineering bandwidth this may be worth revisiting. Again the language simplicity would be worth it. (One day I’ll create a PoC of zero-cost wrapping of std::{fs, net} plus fiber::{spawn, select} using generator!)"
I stand to be corrected but I believe that this is design choice of the Tokio async runtime and not a Rust design choice. For example, the Embassy async runtime does not have this bound but then you have to handle pinning yourself. Also, the static bound is supposed to lower the complexity cost, not raise it.
In a way I feel like I'm going through what is described in the article but for Zig. I guess Zig is more or less in a similar place now to where Rust was back then. Still I enjoy very much using it already.
One benefit of this is that if someone tries and bounces, when they try again a year later their experience might be improved enough that they don't bounce again. For a while I was of the thought that the best piece of advice I could give someone wanting to learn Rust was "wait 6 months" :)
but I cant say the same to Zig because I dont see it as (big) update compared to what we have
Still wherever I need absolute code correctness and production grade quality, I use Rust, my favourite language, at the expense of more code and spending more time doing it "the right way".
IMO, there are things Zig just don’t care about, which in the surface makes it simple but its annoying and burdensome later on.
I was reading an article about rust posted here yesterday and i realized: i have no clue what is going on in this code (also i presume "templage" is a typo):
I love Rust and do some advanced code sometimes, but very rarely have I created a macro. I still see it more or less like "magic" that "super-human" library developers master to make their life easier. Typically not my use case.
This is another advantage of Zig. As you may know, metaprogramming in Zig doesn't use any special syntax, but rather the Zig language itself. This is often known as comptime and while not necessarily easy to grasp, as you're reasoning about compile time stuff, at least it's done in pure Zig.
https://en.m.wikipedia.org/wiki/Zig_(programming_language)
Stuff like
> Also the learning curve for Zig can be steep, especially for those unfamiliar with low-level programming concepts.
I don't think an LLM would start a sentence with "also" like that
> The small and simple syntax is an important part of the maintenance, as it is a goal of the language to allow maintainers to debug the code without having to learn the intricacies of a language they might not be familiar with.
The wording here feels like someone who's a fan of Zig taking a sentence praising Zig's design and trying to rework it into a slightly more neutral encyclopedia style.
[1] https://tably.com/
No comments yet
Noted, and working on it! Pages are copy-on-write as most on the site are intended to be templates where that behaviour makes sense. Working on mitigating annoyances like those observed in these threads. Longstanding browser-specific issues like https://bugzilla.mozilla.org/show_bug.cgi?id=1001790 make this tricky!
> Longstanding browser-specific issues .. make this tricky!
I don't think it's true, there are no browser-specific issues that stand in the way of anything that people are complaining about. Or do you have a PoC in whatever browser?
I suppose if I find anything I really disagree with I can correct it, so that's a bonus.
I would say Rust's borrow checker and lifetimes make it harder to use traditional patterns and favor a more functional approach. Obviously, sometimes doing it the functional way might be hard, for people not so used to it, but it keeps the compiler happier I would say.
When I started out, it felt icky and like some kind of infection that everything eventually had to be async, but that was because I didn't understand how to interact with async code. Using spawn, spawn_blocking, and futures::stream is 90% of my use case, and it makes it easy to set up "barriers" beyond which async doesn't need to spread.
DIP, async/await, coloured-functions, io-monad. All cases where the business logic should go in one column (abstract/sync/blue/pure), and your machinery should go in the other column (concrete/async/red/io). Your logic will remain unit-testable that way, regardless of how big or small it gets.
Irritated newcomers will complain about not being able to call in the other direction. So what's a language-designer to do? Attract the largest possible user-base by not getting in the user's way - or filter out frustrated users and have fewer but better codebases out there?
The typical pattern I enjoy is:
* Sync for the logic
* Async for the job runners b/c I'd like to do other things while it's going.
* Sync or Async as required for the data wrangling (db calls, network, filesystem)
So you have essentially:
1. kick off job, returning a future, by calling an async function.
2. Job is mostly async data wrangling, followed by a sync logic block that's unit tested, followed by an async "save" if required.
3. Either wait for the future, or run the task in the background, or `.await` if you're in an async block.
I'm hand waving away the syntax, but that's the mental model. 99% of code isn't async, and the code that is isn't async for the fun of it.
Especially when using tokio I feel like my solutions work out pretty well. I also very much appreciate how they create async equivalent functions for pretty much any std function worth using. Maybe this creates a divide, but my concurrent programs feel easy to code and the performance is pretty good.
My only semi-issues are probably stuff like task cancellation, however I attribute that to skill issues on my end, rather than tokio or the way async/await is implemented in Rust.
2. I've tried to re-use tab bu typing new URL into URL bar and it doesn't work, browser re-open same page and replace URL back!
WTF?!