Interesting. There’s a JavaScript demo to play around with the syntax at https://eno-lang.org/demo/. Would be neat to get some kind of generic parse tree (JSON?) for an eno document.
I’m a bit unclear on what it means that “all whitespace is optional”, and how to deal with whitespace in values. It appears that leading and trailing whitespace in a field like
Greeting: Hello World
is stripped. It seems that to encode leading whitespace, you need a block:
---Greeting
Hello World
---Greeting
(This is relevant to me as this seems like a possible alternative to YAML that requires less painful indentation while offering raw multi-line blocks. I’m currently using YAML as a format for puzzles, but it’s not perfect, compare puzzle-draw.)
For the generic JSON-like parse tree you can use https://eno-lang.org/javascript/#Section-raw, note however that this debug output tree only contains strings (the parser does not know about your types) and as most elements can be turned into arrays by repetition in eno, most elements are wrapped as such in the raw inspection format by default (here again the parser cannot know :)).
Regarding whitespace you are correct - leading and trailing whitespace is always stripped, except in blocks, where all whitespace is retained verbatim, and your usecase is exactly the thing this mechanism is designed for, would be happy to hear about your experience in case you do try eno to store your puzzles! (Also feel free to get in contact in case of questions or if anything in the documentation can be improved)
Looks like line continuations or escaping might work for including whitespace: https://eno-lang.org/advanced/
Leading and trailing whitespace removal also happens for line continuations (except for the space separator itself which is added in by the parser), escaping only exists for keys, no value in eno ever has to be escaped, that is one of the design principles in the language to keep non-technical users from running into unpredictable and for them often unsolvable behavior. :)
Thanks a lot for helping out! - I’ll take the fact that not everything is clear yet as a nudge for myself to improve documentation in the coming weeks and months! ;)
Always good to read a different take on this subject. One question I have, I wonder if the book answers, is why write a compiler in go? Any advantages or disadvantages?
I have two thoughts on this primarily. If you’re writing a compiler, why not use a language and environment suited for the job? For example the ML family of languages excel at concisely representing algorithms and data structures used for parsing, working with ASTs, etc. But you rarely see compilers written in ML in the wild.
The other thing is; the difficulty of getting good static analysis (for code completion, compile errors, etc) for languages has always been a problem, that’s why there’s been so many different parsers for c++ over the years (Eclipse CDT, QT creators, etc, not to mention ctags et al). Language servers fill this gap. I suppose using go for a language server has appeal due to go’s performance, single executable deployment, gc, and network service friendly nature.
Ha, good question! I’ve previously had to answer it, because, yes, you’re right, there are other languages that are more suited to compiler development. I personally think any language with pattern matching and union types is far more expressive when writing compilers than a language without those features.
But I choose Go not for its expressiveness, but because I personally think that it’s a great teaching language: it doesn’t hide anything, there’s no magic behind any line of Go, you can read Go code even if you’ve never written Go in your life, the standard library contains enough so that we don’t have to get into modules/dependencies, it comes with a testing framework, the standard installation contains gofmt and go test, it’s super stable (you can still run the code from the first version of the first book, written at the beginning of 2016, as it is — that’s not necessarily true for other languages/projects), etc.
That’s the gist of it. I have a few more thoughts on why Go is great for teaching, but I think I should turn those into the blogpost I intend to write :)
…it doesn’t hide anything, there’s no magic behind any line of Go…
Go is a fine and relatively simple language, but I would argue there’s plenty of magic in the M:N threading, GC, structural typing, and runtime reflection.
I certianly won’t argue against any of your other reasons, though.
Ah, yes, you’re right. That can certainly be considered magic, but I was thinking more of the meta-programming magic I know from Ruby.
re ML. For others wondering, here’s a 1998 article on why ML/Ocaml are good for writing compilers. Ocaml is even better at it today thanks its libraries. There’s also metaprogramming extensions to Standard ML that give it some of LISP’s power. Then, there’s people like sklogic whose tool just uses a LISP with Standard ML embedded as a DSL. Drops out of SML whenever its easier to express an algorithm outside of it.
Thank you for linking that! I love the point at the end about languages being toolboxes and some are more suited for certain tasks than others:
But all languages have some problem domains in which they shine. I think that compiler implementation is one of those areas for ML. You’re writing a compiler and in middle of a function you need a 9mm crescent wrench with a box on the other end. You open up your toolkit and … there it is, in the top drawer, bright and shiny and strong. You use it, and then a few minutes later you need a small phillips screwdriver with a clip and a magnet … and there it is, bright and shiny and strong.
It’s not that there are an extraordinary number of tools in the toolbox. (No; in fact, the toolbox is much smaller than the usual toolboxes, the ones used by your friends that contain everything but the sink.) It’s that the toolbox was carefully and very thoughtfully assembled by some very bright toolsmiths, distilling their many decades of experience, and designed, as all good toolkits are, for a very specific purpose: building fast, safe and solid programs that are oriented around separate compilation of functions that primarily do recursive manipulation of very complex data structures.
While I don’t think I agree that it’s a good idea, note that the RISC-V ISA also allows division by zero, producing all-bits-set instead of a trap. (See the commentary in section 6.2 here for their rationale.)
“We considered raising exceptions on integer divide by zero, with these exceptions causing a trap in most execution environments. However, this would be the only arithmetic trap in the standard ISA (floating-point exceptions set flags and write default values, but do not cause traps) and would require language implementors to interact with the execution environment’s trap handlers for this case. Further, where language standards mandate that a divide-by-zero exception must cause an immediate control flow change, only a single branch instruction needs to be added to each divide operation, and this branch instruction can be inserted after the divide and should normally be very predictably not taken, adding little runtime overhead.
The value of all bits set is returned for both unsigned and signed divide by zero to simplify the divider circuitry. The value of all 1s is both the natural value to return for unsigned divide, representing the largest unsigned number, and also the natural result for simple unsigned divider implementations. Signed division is often implemented using an unsigned division circuit and specifying the same overflow result simplifies the hardware.”
Does it also set a flag? If so, that seems perfectly reasonable. The value returned shouldn’t matter as long as you can use out-of-band info to check for divide by zero. Although, I suppose you could just check for zero before the divide… Hmm. So I guess really it doesn’t matter at all. It makes sense to have the result be whatever is easiest to implement.
It appears it just returns the special value with no flags or traps. You have to explicitly check for it on every division. They claim this is to simplify circuitry.
After writing Go for 5 years, I’d recommend Rust for C developers. It’s more complicated than Go for sure, but also has more to offer. The lack of garbage collection and support of generics are definitely a plus compared to Go.
Go is a better language for junior devs, but I wouldn’t call C programmers junior. They should be able to digest Rust’s complexity.
They should be able to digest Rust’s complexity.
Non trivial amount of C programmers are still doing C to avoid additional complexity. Not everyone wants a kitchen & sink programming language.
Rust can definitely get overly complex if the developers show no constraint (i.e. type golf), but the control afforded by manual memory management makes up for it, IMHO. Unless it’s a one-run project, performance will eventually matter, and fixing bad allocation practices after the fact is a lot harder than doing it right from the beginning.
Couldn’t they just start with a C-like subset of Rust adding from there to their arsenal what extra features they like? It’s what I was going to recommend to those trying it for safety-critical use since they likely know C.
I think it’s rather difficult to write rust in a C like manner. This contrasts with go, where you can basically write C code and move the type declarations around and end up with somewhat unidiomatic but working go.
I think C++ as a better C works because you still have libc besides the STL, etc. The Rust standard library uses generics, traits, etc. quite heavily and type parameters and lifetime parameters tend to percolate to downstream users.
Though I think a lot of value in Rust is in concepts that may initially add some complexity, such the borrow checker rules.
The problem with C++ is its complexity at the language level. I have little hope of teams of people porting various tools for static analysis, verification, and refactoring to it that C and Java already have. Certifying compilers either. C itself is a rough language but smaller. The massive bandwagon behind it caused lots of tooling to be built, esp FOSS. So, I now push for low-level stuff either safer C or something that ties into C’s ecosystem.
You could argue the same for C++ (start with C and add extra features). Complexity comes with the whole ecosystem from platform support (OS, arch), compiler complexity (and hence subtle difference in feature implementations) to the language itself (C++ templates, rust macros). It’s challenging to limit oneself to a very specific subset on a single person project, it’s exponentially harder for larger teams to agree on a subset and adhere to it. I guess I just want a safer C not a new C++ replacement which seems to be the target for newer languages (like D & Rust).
It’s challenging to limit oneself to a very specific subset on a single person project, it’s exponentially harder for larger teams to agree on a subset and adhere to it.
I see your overall point. It could be tricky. It would probably stay niche. I will note that, in the C and Java worlds, there’s tools that check source code for compliance with coding standards. That could work for a Rust subset as well.
“I guess I just want a safer C not a new C++ replacement which seems to be the target for newer languages (like D & Rust).”
I can’t remember if I asked you what you thought about Cyclone. So, I’m curious about that plus what you or other C programmers would change about such a proposal.
I was thinking something like it with Rust’s affine types and/or reference counting when borrow-checking sucks too much with performance acceptable. Also, unsafe stuff if necessary with the module prefixed with that like Wirth would do. Some kind of module system or linking types to avoid linker errors, too. Seemless use of existing C libraries. Then, an interpreter or REPL for the productivity boost. Extracts to C to use its optimizing and certifying compilers. I’m unsure of what I’d default with on error handling and concurrency. First round at error handling might be error codes since I saw a design for statically checking their correct usage.
I can’t remember if I asked you what you thought about Cyclone. So, I’m curious about that plus what you or other C programmers would change about such a proposal.
I looked at it in the past and it felt like a language built on top of C similar to what a checker tool with annotations would do. It felt geared too much towards research versus use and the site itself states:
Cyclone is no longer supported; the core research project has finished and the developers have moved on to other things. (Several of Cyclone’s ideas have made their way into Rust.) Cyclone’s code can be made to work with some effort, but it will not build out of the box on modern (64 bit) platforms).
However if I had to change Cyclone I would at least drop exceptions from it.
I am keeping an eye on zig and that’s closest to how I imagine a potentially successful C replacement - assuming it takes up enough community drive and gets some people developing interesting software with it.
That’s something Go had nailed down really well. The whole standard library (especially their crypto and http libs) being implemented from scratch in Go instead of being bindings were a strong value signal.
re dropping exceptions. Dropping exceptions makes sense. Is there another way of error handling that’s safer or better than C’s that you think might be adoptable in a new, C-like language?
re Zig. It’s an interesting language. I’m watching it at a distance for ideas.
re standard library of X in X. Yeah, I agree. I’ve been noticing that pattern with Myrddin, too. They’ve been doing a lot within the language despite how new it is.
Dropping exceptions makes sense. Is there another way of error handling that’s safer or better than C’s that you think might be adoptable in a new, C-like language?
Yes, I think Zig actually does that pretty well: https://andrewkelley.me/post/intro-to-zig.html#error-type
edit: snippet from the zig homepage:
A fresh take on error handling that resembles what well-written C error handling looks like, minus the boilerplate and verbosity.
Short build/edit/run cycles are appreciated by junior and senior developers alike. Go currently has superior compilation times.
Junior and senior developers also enjoy language features such as map, reduce, filter, and generics. Not to mention deterministic memory allocation, soft realtime, forced error checking, zero-cost abstractions, and (of course) memory safety.
Junior and senior developers also enjoy language features such as map, reduce, filter, and generics.
Those are great!
deterministic memory allocation, soft realtime, forced error checking, zero-cost abstractions, and (of course) memory safety.
Where are you finding juniors who care about this stuff? (no, really - I would like to know what kind of education got them there).
I cared about those things, as a junior. I am not sure why juniors wouldn’t care, although I suppose it depends on what kind of software they’re interested in writing. It’s hard to get away with not caring, for a lot of things. Regarding education, I am self-taught, FWIW.
Map, reduce and filter are easily implemented in Go. Managing memory manually, while keeping the GC running, is fully possible. Turning off the GC is also possible. Soft realtime is achievable, depending on your definition of soft realtime.
Map, reduce and filter are easily implemented in Go
How? Type safe versions of these, that is, without interface{} and hacky codegen solutions?
Here are typesafe examples for Map, Filter etc: https://gobyexample.com/collection-functions
Implementing one Map function per type is often good enough. There is some duplication of code, but the required functionality is present. There are many theoretical needs that don’t always show up in practice.
Also, using go generate (which comes with the compiler), generic versions are achievable too. For example like this: https://github.com/kulshekhar/fungen
When people say “type safe map/filter/reduce/fold” or “map, reduce, filter, and generics” they are generally referring to the ability to define those functions in a way that is polymorphic, type safe, transparently handled by the compiler and doesn’t sacrifice runtime overhead compared to their monomorphic analogs.
Whether you believe such facilities are useful or not is a completely different and orthogonal question. But no, they are certainly not achievable in Go and this is not a controversial claim. It is by design.
Yes, I agree, Go does not have the combination of type safety and generics, unless you consider code generation.
The implementation of generics in C++ also works by generating the code per required type.
The implementation of generics in C++ also works by generating the code per required type.
But they are not really comparable. In C++, when a library defines a generic type or function, it will work with any conforming data type. Since the Go compiler does not know about generics, with go generate one can only generate ‘monomorphized’ types for a set of predefined data types that are defined an upstream package. If you want different monomorphized types, you have to import the generic definitions and run go generate for your specific types.
unless you consider code generation
By that definition, any language is a generic language, there’s always Bourne shell/make/sed for code generation ;).
That is true, and I agree that go does not have support for proper generics and that this can be a problem when creating libraries.
I see your point, but “go generate” is provided by the go compiler, by default. I guess it doesn’t qualify as transparent since you have to type “go generate” or place that command in a build file of some sort?
Yes. And for the reasons mentioned by @iswrong.
My larger point here really isn’t a technicality. My point is that communication is hard and not everyone spells out every point is precise detail, but it’s usually possible to infer the meaning based on context.
I think the even larger point is that for a wide range of applications, “proper” and “transparent” generics might not even be needed in the first place. It would help, yes, but the Go community currently thrives without it, with no lack of results to show for.
I mean, I’ve written Go code nearly daily since before it was 1.0. I don’t need to argue with you about whether generics are “needed,” which is a pretty slimy way to phrase this.
Seems to me like you’re trying to pick a fight. I already said upthread that the description of generics is different from the desire for them.
You were the first to change the subject to you and me instead of sticking to the topic at hand. Downvoting as troll.
Compiling a very large go project with a cold cache might take a minute (sub-second once the cache is warm).
Compiling a fairly small rust app with a warm cache has taken me over a minute (I think it’s a little better than that now).
Yes, and superior to Rust in that regard. Also the strict requirement to not have unused dependencies contributes to counteract dependency rot, for larger projects.
I’m certainly no expert in GUI programming, but these guidelines seem to completely miss a major source of complexity: state management and duplication. The immediate mode GUI approach is the only one I’m aware of that minimizes state complexity, though Elm looks pretty close. My shallow understanding is that React provides some of the benefits of immediate mode, but not all of them.
Edit: for an example of how powerful immediate mode GUI programming can be, watch this handmade hero episode, where Casey implements a simple radial menu in under an hour: https://youtu.be/ftZIujU3Udw
In the system I’m proposing, the general rule of thumb is that all state should be visible.
The system will absolutely get hairy. I don’t think that matters much, so long as the hairiness is the product of the primary user & is interacted with frequently enough. In this context, I am opposed to scale.
So I know very little of C and C++. I fell into Go around the time they released v1.0, and I only tried to learn Rust around the same time, when it was still a moving target. At least that’s how I perceived it. Anyway, that’s the long preamble to my question:
I’d like to pick up a new language, and Rust and D both look like interesting candidates. Is there any massive advantage to either one that would make the other a poorer choice?
Rust has a large and active open source community with over 16,000 “crates” available on crates.io. I’m not familiar with D, but it looks like it’s open source package manager, DUB, has ~1,300 packages.
Rust is actively improving with some major improvements (e.g. non-lexical lifetimes, generators, improved procedural macros) currently nearing stabilization, and others (e.g. const generics) planned for the next couple of years.
There’s also a considerable push to make Rust THE language for WebAssembly development, with seemless integration into existing front-end work flows being actively developed by Mozilla engineers.
If you tried to learn Rust when Go 1.0 was released… then the answer to your question is emphatically yes. I was writing Rust before 1.0 came out, and it was intense. It’s nothing even remotely like that these days.
Absolutely. Stable rust is stable. Breaking changes are not allowed except in extreme circumstances, e.g. something very clearly broken. There are features being added fairly regularly, but you can choose to ignore them.
As a side note, there are plans to introduce “epochs” in the release cycle which will be opt-in and allow breaking changes. There’s plans to keep this from fragmenting the community, though. See https://github.com/rust-lang/rfcs/pull/2052 to learn more about epochs.
Edit: I should mention that there are many popular crates awaiting one feature or another before stabilization (1.0 release), but these can also be avoided. The standard library provides enough core functionality for many projects, and you can easily link to C libraries if you need something stable that doesn’t exist as a Rust crate.
I dont use either but read lots of comments. I’m guessing Rust is harder to learn, has slow compiles, and improved safety guarantees w/out performance impact in some hard areas. D lacks that key advantage of no-cost, temporal safety but compiles really fast and may be easier to learn. This is ignoring advanced features in each: Im just saying moving from C, Java, or something to either bringing your existing knowledge. I expect people to be more productive in D with Rust code running faster if it messes with memory a lot.
Any people who know either feel free to corroborate or counter any of that.
Rust was eliminated for lack of nested functions, which is entirely fair. Although I understand why it was not included in Rust (because of safety problems), I sometimes miss it.
Clueless people on HN are arguing why closures are not sufficient. Well, because it’s a different feature.
How is it different? Other than the lack of mutual exclusion enforcement in D, Rust closures seem the same to me. What am missing?
A nested function can modify a variable in the enclosing scope. I don’t think Rust can do that.
https://dlang.org/spec/function.html#nested
Edit: Whoa, whoa, RESF, just one of you was enough.
Rust can do that: http://play.rust-lang.org/?gist=cbedf929dc6ee3a45b8e5fa5787460a4&version=stable&mode=debug
I wrote it a little differently than D’s example because of the borrow checker. It’s just an example after all, so I don’t feel that bad about it, but if you want to be a stickler to match D’s example more precisely, I’d probably just use interior mutability: http://play.rust-lang.org/?gist=16d817b9a819518d2c51436730b48e75&version=stable&mode=debug
Go can also do this as well.
Man, I really have a hard time reading Rust. Why did they have to pick such a weird syntax that looks like nothing else?
Looks fine to me. I was never bothered by it, even when I first started, when the syntax was considerably noisier (before 1.0).
But then again, I can’t remember the last time I ever bothered to complain about the syntax of anything. I realize people disagree with me, but as long as it’s reasonableish, I don’t think it matters very much.
I also think discussions about syntax are mildly annoying, primarily because most of it probably isn’t going to change. Either you’re willing to live with it or you’re not.
edited to soften my language
So it turns out that OCaml is a strong inspiration for Rust and that’s why it looks foreign to me. I didn’t know that.
I don’t know OCaml either, but I have done a fair amount of work in Standard ML. That got me used to the tick marks used as lifetime parameters (type parameters in SML).
Types after names I think is in Go, which I’ve also done a fair amount of work in. I don’t know if Go originated that though. I’d guess not.
Most of the rest of the syntax is pretty standard IMO. Some things are too abbreviated for some folks’ taste, but I don’t really mind, because once you start writing code, those sorts of things just disappear. They are really only weird to virgin eyes. Some other oddities include using ! in macros and perhaps the different syntaxes for builtin pointer types, e.g., &mut T. (Probably defining macros themselves looks really strange too, but there are a relatively small amount of rules.)
Maybe the closure syntax is weird too, I don’t know. I think it’s similar to Ruby’s syntax? I definitely appreciate the terseness, as found in SML, Haskell and heck, even Javascript’s arrow functions, particularly when compared to Python’s or Lua’s longer syntax. Go’s is also mildly annoying because there’s no type inference, and you need to write out the return keyword. But, you don’t use closures as much in Go as you do in Rust as parameters to higher order functions (in my experience) because of the lack of generics. It’s for loops all the way down.
As long as it’s within a broad realm of reasonableness, syntax mostly just bleeds into the background for me.
It’s also worth mentioning that the use of interior mutability can lead to more noise in the code, especially in an example as terse as the one up-thread.
You can if the closure borrows a reference to the value (which is necessarily how it works in D). Sharing a mutable reference requires an explicit Cell/RefCell/UnsafeCell, though. UnsafeCell would presumably have the same semantics as in D.
Edit: Whoa, whoa, RESF, just one of you was enough.
Instead of being a troll about it, you might consider that we all started responding around the same time and didn’t know others had already done so. (e.g., When I clicked post, Steve’s comment wasn’t on my page.)
Well, the RESF is pretty strong. I make one off-hand wrong comment and three of you, whether intentionally or not, jump on it. I practically never get that many comments in quick succession in Lobsters. I obviously struck a nerve by speaking a falsehood that must be corrected immediately.
I’m also slightly unhappy that we can’t ever talk about D without “I would like to interject for a moment, what you are referring to as D is in fact Rust or as I’ve taken to calling it, CRATE+Rust”.
I called out the RESF effect here. Hit Twitter immediately haha. Ive been keeping an eye out since. Ive seen no evidence of an active RESF here or on HN. Just looks like a mainstream language with a lot of fans, areas of usefulness, and therefore lot of comments. I see more comments about Go than Rust.
And then there’s Pony. Now, that one comes across as having an evangelism team present. ;)
that one comes across as having an evangelism team present
Where? :) I’d like to read more actual articles about Pony, but all I’ve seen so far are links to minor release announcements…
It was an inside joke about the Pony fan club we have here on Lobsters. Sometimes I see more Pony articles than those for mainstream languages. They usually have plenty of detail to be interesting enough for the site. Only exceptions are release submissions. I’m against release submissions in general being on this site since people that care about that stuff will likely find the release anyway. Might as well use that slot for something that can teach us something or otherwise enjoyable.
The OP mentions Rust, and you were talking about it too. Scanning the posts tagged with D, I see exactly one substantive discussion involving Rust other than this thread. So I’m going to have to call shenanigans.
Well, the RESF is pretty strong.
Just stop. If you have an issue, then address it head on instead passive aggressively trolling.
D and Rust are used to solve similar sets of problems. This invites comparisons, not just on the Rust side but on the D side too. A lot of people who haven’t used Rust get their claims mixed up or are just outright wrong. I see nothing bad about politely correcting them. That’s what I did for your comment. What do I get in exchange? Whining about syntax and some bullshit about being attacked by the RESF. Please. Give me a break.
Do you want to know why you don’t see me talking about D? Because I don’t know the language. I try not to talk about things that I don’t know about. And if I did, and I got something wrong, I’d hope someone would correct me, not just for me, but for anyone else who read what I said and got the wrong idea.
TBH sounds apocryphal. The system was in a building away from the tracks, no living thing can give out that amount of ionizing radiation while still, well, living.
Obligatory Taco Bell programming.
If this is just for interconnects, I can’t think of any reason you would use this over carbon nanotubes or graphene, either of which would have a higher conductivity (as pointed out in the article).
If there are other interesting electrical (or phsycial) properties, then I could potentially see this material (or similar 1D materials) being more useful than the 2D materials that are all the rage in materials research right now. 1D is a much better fit for ultra-scaled devices. 2D materials are, as far as I can tell, little more than hype.
This is actually a fairly compelling idea. More compelling than most applications of block chain, in my opinion. It’s true value would require all code to be open-sourced, though. Is that the plan?
As a (primarily) C programmer who has been eyeing Rust from a distance with some interest, the author makes a number of compelling points – but from what I’ve read elsewhere…
No integer overflow
Enough said.
No, very much not enough said – if this is an issue you care about, this is a gross oversimplification. Such a description might be accurate for a language with automatic bignum-promotion, where integer overflow can be really said to (within the bounds of memory) actually not happen – Python, say. But the situation in Rust, while yes, probably preferable to the one in C in most ways, isn’t that simple.
Yeah, it wasn’t obvious to me why that was ”enough said.” I use (unsigned) overflow on purpose quite a lot in audio programming.
I think it’s nice how Swift made overflow trap, using regular arithmetic operators, but added versions prefixed with & to opt-out, e.g. &+.
In case you didn’t check the article 1amzave linked:
Rust has .wrapping_<op> methods for 2’s compliment arithmetic (and a few other variants, saturating, checked - which gives a handable error on overflow, overflowing - which wraps and tells you if it wrapped), as well as a Wrapping<T> type that makes the normal operators wrapping.
It doesn’t have a fancy &+ syntax though, which is probably a good thing IMO given how rarely wrapping arithmetic is used in general.
Yes, I didn’t know about those before coming here for the comments!
&+ is not really special syntax in Swift though, since it allows user-defined operators, for better or worse.
Rust panics on overflow by default, but provides functions that explicitly allow integer overflow wrapping, as well as functions for checked arithmetic and saturating arithmetic:
https://doc.rust-lang.org/std/primitive.u32.html
This seems like the best of all approaches to me.
Rust panics on overflow by default
But not in release mode. (This has bitten me, painfully!) Worth being vigilant while coding in case your code might run into edge cases in production it doesn’t in test.
Thanks for pointing that out! I somehow missed that important detail. I’ll have to keep that in mind!
Wow, I hadn’t thought of the huge change automotive is facing. This article makes the point that current fleets sit unused the majority of the time, but a properly implemented self-driving fleet will be in use nearly 100% of the time. That’s a big change in the needs of the parts.
I live in a cold climate and parts for automotive need to withstand -40 (both C and F, they’re the same). I wonder if we’ll see vehicles that aren’t designed for this because they’ll be in use all the time and won’t sit still long enough to get that cold. Of course now that I think of it, this would not really adversely affect the ICs (topic of this submission), more the mechanical and specialized parts (LCD displays, etc).
While the cold wouldn’t adversely effect the ICs in the long term, if they get cold enough, they’ll temporarily stop working as the electron occupancy of the valence bands drops. Practically, this means that your car computer will fail to boot if it gets too cold.
Which, I guess, is a long winded way of saying that the design constraints don’t change much for the electronics.
At sufficiently high doping, it becomes basically impossible to freeze out the dopants, because a Mott band forms. Essentially, the dopant radiuses begin to overlap, forming a partially filled conduction band.
CMOS chips run just fine at 77K.
This is an interesting idea, but the TCP checksum based implementation leaves much to be desired. It certainly places some practical restrictions on the desired complexity of public-facing communications protocols.
Thanks for making this! I’ve recently left my job at Intel PTD in order to move back to Austin. I’d love to talk to other lobsters to see what opportunities are out there! I just sent a request to join!
It seems like all of these issues could be resolved if the processor’s microcode (or the OS’s kernel) had explicit control over cache invalidation. Any microarchitecture researchers here that can comment on the existence of or any research on explicit cache control?
I’ve always wondered why the cache can’t be controlled explicitly, even in user mode code. It seems like a lot of performance is probably left on the table by having it automated. It’s like how using garbage collection (GC) can simplify code, but at the cost of throwing away information about memory usage and then having the GC try to guess that information in real time.
My understanding (from David May’s lectures and asking lots of questions) is that memory caches are far too much on the hot path (of everything, all the time) to be controlled by microcode.
I remember he mentioned some processor (research? not mainstream, I think) being made with a mechanism wherein you could set a constant in a special register that would be added to the low bits of every physical address before it hit the cache system, so that you could have some user level control of which addresses alias each other. But I got the impression from that conversation that nobody had ever really seriously considered putting anything more than one adder’s worth of gate delays for user control of a cache system because it’s so important to performance and nobody could think of amazingly useful ways that running code could customise cache behaviour that can’t already be achieved well enough anyway using CPU features like prefetches or by cleverly changing the layout of your data structures.
I could image separate load/store instructions for uncached memory access, for example. ARM already has exclusive load/store in addition to normal ones.
Why is that? Afaik the only alternative is directory-based which has higher latency but scales better.
You could design for non-coherent caches with software controlled cache line sync. Most data is not shared but the overhead for shared data is imposed on all transactions.
Software control is probably even slower. One problem is that the compiler has to insert the management instructions without dynamic information like a cache, which means a lot of unnecessary cache flushing.
If you go for software controlled, I would rather bet on fully software managed scratch pad memory. There seems to be no consensus how to use that well though.
Very few memory locations are shared - probably fewer should be shared. Snooping caches are designed to compensate for software with no structure to shared variables.
Looking at the Spectre proof of concept code, it looks like there already actually is a way for user mode code to explicitly invalidate a cache line, and it’s used in the attack.
Perhaps a microcode patch could use this feature of the cache to invalidate any cache lines loaded by speculative execution?
I prefer keeping it simple and general by using self rather than &mut self. If you make the builder’s members public (which doesn’t mean the final struct’s members need to be public), then you can handle more complex cases with direct member access:
let mut builder = OutboundCallBuilder::new("tom", "jerry", "http://www.example.com");
if (need_fallback) {
builder.fallback_url = Some("http://www.fallback.com");
}
let call = builder.build();
The piece links to this post, which is a fascinating deep dive into the implementation and bug fix/enhancement of a vector datatype meant to be especially performant in cases where its length is small (SmallVec), but was actually slower and unsound (remedied by the post’s author for both ills):
http://troubles.md/posts/improving-smallvec/
I don’t really understand the “and why you shouldn’t care” part of the title; there’s never another reference to why you shouldn’t care.
I think the “why you shouldn’t care” was in reference to Vec being just as fast in most use cases.
I can maybe see that, but when all was said and done, SmallVec was faster than Vec in the case that it was small enough and used such that it could be allocated on the stack, which was the motivating use case for its existence. That seems like something I would care about, if I had cared to try to optimize my code by using SmallVec instead of Vec. Its disadvantage over Vec in an application would likely be hard to localize without specific microbenchmarks, I’m betting, so the fact that it was counterproductive could easily have slipped by even if attention was being paid to performance overall.
I guess the very last sentences support your conclusion (“If you’re using smallvec for its performance benefits, it’s worth benchmarking your program using Vec with Vec::with_capacity instead. Usually the simpler implementation is the faster one.”) but I still think the headline is sub-optimal; you have to care enough to benchmark still! Regardless, the piece overall (as well as the OP) is still pretty great.