(Also all the hype and fearlessness is obnoxious)
With such a strong focus on bounds checking, are there any 'systems programming' languages that you do find acceptable?
Unsafe blocks don't change the semantics of code, they just let you write code you couldn't write outside of them.
> So, for me, the placing of bounds checks when using that function is an implementation detail and therefore, if unsafe removes it, it does not effect the semantics.
The function is not marked as unsafe, so it promises that it will not corrupt memory and thus must perform bound checks. The designation of safe/unsafe for a function is compile-time and promises certain semantics.
It would be a semantic issue for a safe function to invoke unsafe behavior.
Even within an 'unsafe' block, calling safe functions should not cause memory corruption as long as your other unsafe calls / unsafe code didn't do anything "wrong".
Anyway, to implement a function like that, you'd need:
fn index(i) -> T {
if is_caller_in_unsafe_block() {
return unsafe { unsafe_index(i) }
} ...
}
The compiler does not, as far as I'm aware, have any "is_caller_in_unsafe_block" primitive, and adding one seems quite fraught.That's exactly why I get annoyed. How will it be fast if it branches on every access
> where the compiler could 'prove'
The compiler doesn't prove shit. It lets the optimizer do it. It's extremely easy to fool the optimizer
> there any 'systems programming' languages
The ones that don't make false claims (so not v or rust) and don't insert code I don't want
And random access `array[intval]` will always be performance crippled if intval is provided by external system at runtime.
Even if intval is guaranteed to be between 0..<array.length, you need to converted it to that type.
What I want is a check outside of the loop then every access inside a loop unchecked and fast. Which isn't what rust does. Then it throws your memory away if you did an oops and went out of bounds
That's exactly what iterators allow.
I tend to treat iterators as a non-factor when discussing semantics of a language as I will always default to them not being a 'language-level' construct. I am not a fan of iterators in any case, but then again, I don't particularly like any higher level constructs in my 'run-time' code.
* https://github.com/mike-barber/rust-zero-cost-abstractions
* https://carette.xyz/posts/zero_cost_abstraction/
* https://ruudvanasseldonk.com/2016/11/30/zero-cost-abstractio...
I don't disagree that the translation may result in roughly similar assembly/bytecode instructions in many languages, and while TFA is Rust-centric and most of the conversation has been too, my issues with iterators are not restricted to Rust. Further, my objection to using them in my own code is not strictly a performance issue (although, I am never in favor of coding and hoping it gets optimized).
Inherently, iterators are a more complex concept than a loop (or the tail recursive equivalent). Iterators are an object in and of themselves that are by design more complex than a natural number index, then you still need the actual looping construct. I am aware there are reasons that iterators are preferred and often recommended in some situations. However, the determination to use an iterator based construct in your code is not a universal declaration of fitness, it is only a case-by-case determination weighed against whatever other factors matter to the people writing the code. I also think this applies to the pushing of iterators as an idiomatic construct in a programming language, i.e. whether iterators are idiomatic is a determination that is made by the language designers when weighed against the established goals and priorities of the language as a whole.
Regarding the iterator-based code enabling optimizations that make the resulting compiled code faster than a basic while loop: I will admit that there is a possibility for this to occur. However, that is tempered by an educated guess that the enabling of those optimizations only occur because the compiler writers have explicitly coded in a 'hot-path' for iterator constructs into the IR. Also, there is the chance that the compiler writers use the higher level IRs to memoize data about the loop as a whole (based on knowledge of the language's iterator construct) and the presence of that data at later stages of the compiler allow for optimizations to occur, whereas the while loop would not trigger the memoization steps and then could not produce the optimizations. Both of those circumstances are a result of the language designers/compiler writers basing code generation (or IR generation) off of the idioms of the language and the underlying semantic definitions of the language.
As an aside, I am not certain Rust's compiler treats iterators the way I described above, but I would be surprised if it was not.
The closest thing to an argument I am making is that iterators are a different language construct than a basic looping construct. If you disagree that’s fine, like I said, I’m not trying to ‘win’ anything or convince anyone of anything.
Edit to refer to sibling comment — As I said in a sibling comment, the iterator loop construct is syntactic sugar and that’s why I was saying it is different from discussing a more basic looping construct.
I would have to check the intermediate language, but I assume the for in construct is implemented, at the semantic level as an iterator object inside a while or basic loop construct.
Edit — I just checked and docs.rust-langexplicitly states that the for in construct is ‘syntactic sugar’ for the common case of looping over a container that implements the iterator trait.
You can increment a number yourself, but at that point you're doing something where there is significantly better language support for just using iterators. You may as well claim Rust has semantic support for, idk, bubblesort, because you can write bubblesort with it.
'or-in-loops, or to be more precise, iterator loops, are a simple syntactic sugar over a common practice within Rust, which is to loop over anything that implements IntoIterator until the iterator returned by .into_iter() returns None (or the loop body uses break).' [1]
In fact that same page gives the expanded code on it. It directly expands to code using the iterator's .next() method on each go through the loop. So, I think since the difference between the iterator semantics, as defined and describe by the Rust documentation, and using an index variable and incrementing that variable on each loop are not different enough for your exaggerated claim regarding 'semantic support'.
But, I'm not trying to convince you to not use iterators or that iterators are not useful in some projects. I don't particularly care what other developers decide are the correct standards for their projects. My initial comment for this sub-thread was just trying to point out that I tend to view a language's semantics at the base level, where iterators are programmer implemented features defined for specific types, and that there is a definite difference between using iterators and using a loop with an index variable for container access. I don't think I was wrong to make that observation, and the Rust docs seem to support that difference. That's all I was getting at.
At a "base level", every language is exactly equivalent - they are all approximations of a turing machine - so I really don't get that argument unless you are trying to argue that every language is really just C in disguise.
for i in 1..n {
some_mut_arr[i] = T::default();
}
// OR
mut i = 0;
while i < n {
do_something(some_arr[i]);
i += 1;
}As for the while loop "torturing the poor language" - that's you injecting some preference. It's perfectly valid rust, and there's plenty of situations that look close to what I wrote (albeit my example was distilling down those cases to the core) and which aren't easily achievable without contortion to get everything into an iterator.
Don't get me wrong - I really like iterators. Sometimes though, iterators add obfuscation, particularly after the 5th or 6th chained iterator method.
So just as Rust's "for" is syntactic sugar, so is "while", it will de-sugar into loop with an exit condition break at the start, since that's how while works in Rust.
But this sort of illustrates how limited your model is, you're assuming the way loops worked in some language you've more experience with, probably C, is just "how loops work" but it's a weird feature of one language invented decades before the present, but decades after the fundamentals. It's like fixating on how the brakes worked on the 1971 Ford Cortina. That's not "how car brakes work" it's just how the brakes worked on that particular model of car, a brand new BMW i4 and a Model T are both equally reasonable examples of "how car brakes work".
> What I want is a check outside of the loop then every access inside a loop unchecked and fast
That's what Iterators give you.