Lowering demand doesn't always lower price. Assuming the industry is competitive, and capable of supplying all demand, which it usually is, the loss of demand mostly means less money for the producer, and more money for the former consumer to spend on something else.
Programming languages, like natural languages, are tools for human beings, not computers. They work around the strengths and weaknesses of a human brain.
It's not a question of being smart or stupid. It's whether the tool fits the task it's applied to and the affordances it gives the user.
Scheme is intended more as a teaching tool than an actual language. Its simplicity is perfect for reasoning about programs. It's less well suited to practical tasks.
About the only really difficult lesson of Scheme is if you use it as a purely declarative language. Imperative features are a natural affordance of the human brain. Working with them is beautiful and alien.
I don't know you, but it seems very unlikely. scheme is a little different because it doesn't really encode or enforce 'standard patterns' that serve as mold that we pour code into. that probably means that its not quite as clear where to start. but at least in r4rs-land its based on a very small number of general simple primitives.
I think it's refreshing change of perspective, and certainly worth pursuing if you're interested at all in in building programming structures rather than just using them. but if its not at all to your taste I wouldn't beat yourself up about it.
Very nice work for how small the source code is, and this is a relatively good design for the language.
I will say to criticise that I started scratching my head when I got to the standard library. The functions should really just be C's standard library. I know there's lots of baggage but e.g. remembering that 'print(s)' will print with a newline and 'printn(s)' won't, this is just putting a barrier to entry that's not necessary. Sure, have some new functions for slices, but if you can help it use more conventional names from C.
> If you maintain a site that uses asm.js, nothing will break. asm.js is just a subset of plain JavaScript, so the code keeps running through our regular JIT just like any other script.
And this is still a killer feature of asm.js, even if it's not 'supported' it's still implicitly supported.
EDIT: And also seriously just thanks to the people who invented asm.js, it was a brilliant idea, but it makes sense that it's not worth optimizing anymore.
So it's just as useful as when your stack area ends with a page that will segfault on access, or your CPU will raise an interrupt if stack pointer goes beyond a particular address?
It's not safe though because throwing an exception, panicking, etc, is still a denial of service. It's just more deterministic than silently overwriting the heap instead. If the program is critical then you need to be able to statically prove the full size of the stack, which you can do with C and C++ with the right tools and restrictions.
You're mixing specification (a language reference manual) and implementation (a given compiler, target, options, ...).
The Ada language specification says the Ada programmer can expect any Ada compiler when used in fully compliant mode to properly raise STORAGE_ERROR when a stack overflow occurs.
Only the Ada compiler writer has to deal with this, not every single programmer on every single program and platform (the UB behaviour of some languages).
In the case of GCC/GNAT the compiler manual provides insight on how to be in compliant mode per target regarding stack overflow, what are the limitations if any. You have tools to monitor and analyze you Ada code in this respect too.
Deterministic, well-defined behavior is inherently safer than undefined behavior. It allows you to diagnose the problem and fix it. UB emphatically does not, and I don't dare to think of how many millions of person-hours are wasted every year dealing with the results.
A segfault is considered safe if you're talking about functional safety because it results in a return to a defined safe state (RTDSS).
If a segfault leads to some other state you do not deem "safe", such as a single program gating access to a valuable asset with a default fail state of "allow", you just have a fundamental design flaw in your system. The safety problem is you or your AI agent, not the segfault.
A reliable 'denial-of-service' is better than silently doing the wrong thing.
> If the program is critical then you need to be able to statically prove the full size of the stack, which you can do with C and C++ with the right tools and restrictions.
Only for specific implementations; and neither C nor C++ standard guarantee that your program won't overflow the stack anyway. (Have a look, the standard says nothing about stack overflows, they still occur in practice with supposedly compliant compilers. So it seems that there are no rules about when they can happen.)
Although some people, like Bjarne Stroustrup, object to the term C/C++, it's a bit like Richard Stallman objecting to the term "Linux". The fact is it can mean "C or C++", and I wouldn't assume the author thinks they're the same, but they're talking about both of them together in the same sentence. This seems reasonable given this is about undefined behavior, and it's trivial to accidentally write UB-inducing code in C++ even with modern style (although I'd say you should catch most trivial cases with e.g. ubsan, and a lot of bad cases would be avoided with e.g. ranges, so I think the article is exaggerating the issue).
3.16 undefined behavior: Behavior, upon use of a nonportable or erroneous program construct, of erroneous data, or of indeterminately valued objects, for which this International Standard imposes no requirements. Permissible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message).
Is it just me or did compiler writers apply overly legalistic interpretation to the "no requirements" part in this paragraph? The intent here is extremely clear, that undefined behavior means you're doing something not intended or specified by the language, but that the consequence of this should be somewhat bounded or as expected for the target machine. This is closer to our old school understanding of UB.
By 'bounded', this obviously ignores the security consequences of e.g. buffer overflows, but just because UB can be exploited doesn't mean it's appropriate for e.g. the compiler to exploit it too, that clearly violates the intent of this paragraph.
Notice though "ignoring the situation" thru "documented manner characteristic of the environment". Even though truly you can read this in an uncharitable way, you could also try and understand the intent of this paragraph, and I think reading it for its intents is always the best way to interpret a language standard when the wording is ambiguous or soft, especially if you're writing a compiler.
I don't think you could sincerely argue that this definition intends to allow the compiler to totally rewrite your code because of one guaranteed UB detected on line 5, just that it would be good to print a diagnostic if it can be detected, and if not to do what's "characteristic of the environment". Does that make sense?
Bounding UB would be a nice idea, or at least prohibiting time-traveling UB (and there is an effort in that direction). But properly specifing it is actually hard.
Even if you forbid "time travel", you can still technically optimize many things as if time travel happened anyway - e.g. want to time-travel back to before some memory store? just pretend that the store happened, but then afterwards the previous value was stored back (and no other threads happen to see the intermediate value)!
Only things you need to worry about then are things with actual observable side-effects - volatile, printf and similar - and C23 does note that all observable behavior should happen even if UB follows, and compilers can't generally optimize function calls anyway (e.g. on systems on which you can define custom printf callbacks, you could put an exit(0) in such, and thus make it incorrect to optimize out a printf ever).
When would optimizing correct code be harmed by not abusing UB (beyond its original intent, e.g. array access should be without overhead of checking for overflow)?
> Notice though "ignoring the situation" thru "documented manner characteristic of the environment".
I noticed that. Those are 100% consistent & implied by the parts of the standard I quoted that you are ignoring, though.
What you're doing is:
- Arguing is that those phrases describe the totality of the implications, rather than mere examples, without providing anything to base this method of argumentation on.
- Completely ignoring the other phrases I quoted, which (taken at face value) contradict your reading.
- Claiming that anyone who disagrees is being insincere(?) and reading the standard uncharitably.
- Not even attempting to support this line of reasoning through other arguments.
So you're not only asking people to read contradictions into the standard, but also insinuating that people who don't are not arguing in good faith. That... honestly isn't a winning strategy.
Note that I'm not even saying your conclusion regarding their intent is necessarily wrong. I'm just saying your argument is bad. And that there is a difference between what the rules are and what some people believe their authors intended them to be.
If I wanted to argue your position, I would look for other parts of the standard where they do what you're claiming. That is, where the literal meaning of the wording would be crazy, and which would clearly contract what everyone believes the authors of the standard intended it to mean. Then you would at least have some basis for extrapolating that line of reasoning to this paragraph. At that point you might at least get an acknowledgment from the other side that the standard is unclear and/or has a defect, even if they didn't agree with your take on what requirements it imposes as-written.
> I don't think you could sincerely argue that this definition intends to allow the compiler to totally rewrite your code because of one guaranteed UB detected on line 5,
I'm not sure if you're exaggerating ("totally"?), being sloppy, or misunderstanding, or if you actually mean this literally, but I already don't believe it does that, and I have never seen any compiler interpret it that way either. Sorry, but you're going to have to be more precise and pedantic here so you actually have something realistic to argue against. Right now it looks like you have an impression of UB that doesn't match reality.
> Completely ignoring the other phrases I quoted, which (taken at face value) contradict your reading.
You are taking them out of context (literally this is what you describe here, taking at face value a smaller quote).
I think your approach to interpreting the spec is not correct. This isn't code, it's a spec: it needs to be read in full context (even though a good spec would certainly be written in a less context-sensitive way, this is not a perfect spec -- have you ever seen one?). You're not a computer or a machine, you need to read it more like a human, even though we're all trained on the concrete mechanics of computer programming. Yes, even though it's describing a programming language, believe it or not. All specs have flaws and need nuance in those situations or you will either (for language specs) write code that doesn't work anywhere, or you will write a compiler that breaks code matching what the authors of the spec intended to allow.
> Right now it looks like you have an impression of UB that doesn't match reality.
I have an impression of UB that is not the convention, my post is criticising the convention. I am trying to give context and nuance where it is unfortunately lacking and now apparently quite relevant to lots of people. This can't change reality of current compilers, but maybe it can serve as a lesson in history.
I touched on this in the "it's not about optimizations" section. It's not the compiler is out to get you. It's that you told it to do something it cannot express.
It's like if you slipped in a word in French, and not being programmed for French, it misheard the word as a false friend in English. The compiler had no way to represent the French word in it's parse tree.
So no, it's not overly legalistic. Like if the compiler knows that this hardware can do unaligned memory access, but not atomic unaligned access, should it check for alignment in std::atomic<int> ptr but not in int ptr? Probably not, right?
It's not that your article specifically discusses this aspect, but I think it's an important part of the conversation that's being overlooked by commentators, that we've twisted the original intent of UB and made unnecessary work for ourselves. There's been too much scaremongering about UB that's gone beyond the real concerns. If you only fear UB and don't understand it then you are worse off for trying to write safe C or C++.
The behaviour is bounded by the capability of your machine. It is unlikely that your desktop computer launches a nuclear missile, unless you worked for it to be able to do that.
> Is it just me or did compiler writers apply overly legalistic interpretation to the "no requirements" part in this paragraph?
I've (fruitlessly) had this discussion on HN before - super-aggressive optimisations for diminishing rewards are the norm in modern compilers.
In old C compilers, dereferencing NULL was reliable - the code that dereferenced NULL will always be emitted. Now, dereferencing NULL is not reliable, because the compiler may remove that and the program may fail in ways not anticipated (i.e, no access is attempted to memory location 0).
The compiler authors are on the standard, and they tend to push for more cases of UB being added rather than removing what UB there is right now (for exampel, by replacing with Implementation Defined Behaviour).
This adds a little context behind why when I lived in Bromley I was always told to write "Kent" on post, even though I wasn't in Kent. Apparently it was indeed fully in Kent at some point.
The non-obvious thing that's supposedly still required now is the "Postal Town". By non-obvious I mean it's not obvious what the postal town would be for villages miles away from any town.
A correct Postcode is much more specific and overrides the need for a Postal Town.
The vast majority of Royal Mail addresses are analysed automatically (google "royal mail ILSM") and then this info is encoded on the special RM4SCC barcode and machine read from that point on. It drops back into human sorting once it's got to the local delivery office.
There's still the small group within Royal Mail who do their best to work out where to deliver items with incomplete, incorrect or cryptic addresses. Plenty of examples of people getting mail successfully delivered with addresses like:
Lady with a big white dog (Sarah? The lady not the dog)
Said she lives next to a small church
Some village in East Suffolk with a short name
(Note the oddities link above demonstrates that "building name/number + postcode" is not guaranteed to be unique, although the number of duplicates is quite low.)
I used to work with a company in Somerset whose official address is "The Barn on Church Lane". Never had any problems with shipping or mailing, but had many discussions over the years with American clerks who wouldn't believe it was a valid address.
reply