The issue with the while is that more often than not you need to do some preparations before the condition. So you need to move that to a function, or duplicate it before and inside the loop. Do-while doesn't help, since with that you can't do anything after the condition.
The alternative is a while(true) with a condition in the middle.
while(true){
prepare;
if(!check) break;
process
}
But what if there was a language construct for this? Something like
do{prepare}while(condition){process}
Is there a language that implements this somehow? (I'm sure there is, but I know no one)
The best thing is that this construct can be optimized in assembly perfectly:
...
jump-always > start
after:
process
start:
prepare
condition
branch-if-true > after
...
Evaluates foo, then bar(s), and returns the result of evaluating foo and discards the results of bar(s).
Useful if `foo` is the condition and you need to perform some change to it immediately after, eg:
(while (prog1 (< next prev) (setq prev next)) ...)
---
(prog2 foo bar baz*)
Evaluates foo, then bar, then baz(s) (if present), returns the result of evaluating bar and discards the results of evaluating foo and baz(s).
Might be what GP wants. `foo` is the preparation, `bar` is the condition`, and `baz` can be some post-condition mutation on the compared value. Not too dissimilar to
for (pre, cond, post) {}
With `prog2` you could achieve similar behavior with no built in `for`:
(while (prog2 pre cond post) ...)
---
(progn foo*)
Evaluate each foo in order, return the result of evaluating the last element of foo and discard all the others.
`progn` is similar to repeated uses of the comma operator in C, which GP has possibly overlooked as one solution.
Learning to embrace the LOOP construct has been an experience, for me. Same with the FORMAT abilities. It is amazing how much hate they both get, for how capable they both are.
C-style for-loop is kinda sorta this. Although the "prepare" part has to be an expression rather than a statement, given that you have the comma operator and ?: you can do a lot there even in C. In C++, you can always stick a statement in expression context by using a lambda. So:
for ([]{
/*prepare*/
}(); /*condition*/;) {
/*body*/
}
However, the most interesting take on loops that I've seen is in Sather, where they are implemented on top of what are, essentially, coroutines, with some special facilities that make it possible to exactly replicate the semantics of the usual `while`, `break` etc in this way: https://www.gnu.org/software/sather/docs-1.2/tutorial/iterat...
In some way it's the dual of break, in that you want to jump into the middle of the loop, while break is to jump out of it.
Let's rewrite the loop this way, with 'break' expanded to 'goto':
while (true) {
prepare...
if (!cond) goto exitpoint;
process...
}
exitpoint:
The dual would be:
goto entrypoint;
do {
process...
entrypoint:
prepare...
} while(cond);
Both constructs need two points: where the jump begins and where it lands. The 'break' is syntactic sugar that removes the need to specify the label 'exitpoint'. In fact with 'break' the starting point is explicit, it's where the 'break' is, and the landing point is implicit, after the closing '}'.
If we want to add the same kind of syntactic sugar for the jump-in case, the landing point must be explicit (no way for the compiler to guess it), so the only one we can make implicit is the starting point, that is where the 'do' is.
So we need: a new statement, let's call it 'entry', that is the dual of 'break' and a new semantic of 'do' to not start the loop at the opening '{' but at 'entry'.
do {
process...
entry;
prepare...
} while (cond);
Is it more readable than today's syntax? I don't know...
do {
Get(Current_Character);
if (Current_Character == '*') break;
print(Current_Character);
} while (true);
I don't see why this needs a new construct in languages that don't already have it. It's just syntactic sugar that doesn't actually save any work. The one with the specialized construct isn't really any shorter and looks pretty much the same. Both have exactly one line in the middle denoting the split. And both lines look really similar anyway.
Well, I am in a process of making a language where general loops will look like
loop
prepare;
while check;
process;
end;
I also think you'd enjoy Knuth's article "Structured Programming with go to Statements" [0]. It's the article that gave us the "premature optimization is the root of all evil" quote but it's probably the least interesting part of it. Go read it, it has a several sections that discuss looping constructs and possible ways to express it.
do {
let value = prepare();
} while (value.is_valid) {
process(value);
}
Can the second block of the do-while see `value` in its lexical scope? If yes, you have this weird double brace scope thing. And if no, most non-trivial uses will be forced to fall back to `if (...) break;` anyway, and that's already clear enough imo.
The scope should be unique, yes. In your example value should be visible.
Your are right about the word double braces, but I can't think of an alternate syntax other than just removing the braces around the while. But in that case it may seem odd to have a keyword that can only be used inside a specific block...wich is basically a macro for a if(.)break;
Maybe I'm too used to the c/java syntax, maybe with a different way of defining blocks?
That seems more like a programmer expectations issue than something fundamental. Essentially, you have "do (call some function that returns a chunk of state) while (predicate that evaluates the state) ..."
Hard to express without primitives to indicate that, maybe.
Yeah, `while...else` in Python does the wrong thing. Executes `else` block when the loop finished normally (not through `break`).
Scala for example has a `breakable {}` block that lets you indicate where you should land after a `break`
breakable {
while condition {
// loop body
if otherCondition then break;
// rest of the body
}
// body of pythonic else block
} // you land here if you break
However I have no idea how to implement the kind of `else` I described in any language without checking the condition twice.
You mean like a shell's while-do-done? It's just about allowing statements as the conditions, rather than just a single expression. Here's an example from a repl I wrote:
repl_prompt="${repl_prompt-repl$ }"
while
printf "%s" "$repl_prompt"
read -r line
do
eval "$line"
done
echo
The `printf` is your `prepare`.
This should also be doable in languages where statements are expressions, like Ruby, Lisp, etc.
Here's a similar Ruby repl:
while (
print "repl> "
line = gets
) do
result = eval line
puts result.inspect
end
puts
Exactly, here you are basically keeping it as a while with a condition but allowing it to be any code that at the end returns a boolean, although you need to make sure that variables defined in that block can be used in the do part.
Sidenote: I wasn't aware that shell allows for multiple lines, good to know!
PowerShell can process 0..n input objects from the pipeline using BEGIN {...} PROCESS {...} END {...} blocks.
I find this so incredibly useful, that I miss it from other languages.
Something related that I've noticed with OO languages such as Java is that it tends to result in "ceremony" getting repeated n-times for processing n objects. a well-designed begin-process-end syntax for function calls over iterables would be amazing. This could apply to DB connection creation, security access checks, logging, etc...
This runs all 3 in order every iteration but quits if condition evaluates to false. It just uses the fact that value of a block is the value of the last expression in the block.
Scala has a lot of syntax goodies although some stuff is exotic. For example to have a 'break' you need to import it and indicate where from exactly you want to break out of.
I don't write a lot of while loops so this is just a bit unfamiliar to me, but I'm not really understanding how this isn't the same as `do{block}while(condition);`? Could you give a simple example of what kind of work `prepare` is doing?
Think of a producer (a method that returns data each time you request one, like reading a file line by line or extracting the top of a queue for example) that you need to parse and process until you find a special element that means "stop".
I'm aware this example can be trivially replaced with a while(data=parse(producer.get())){process(data)} but you are forced to have a method, and if you need both the raw and parsed data at the same time, either you mix them into a wrapper or you need to somehow transfer two variables at the same time from the parse>condition>process
A do-while here also has the same issue, but in this case after you check the condition you can't do any processing afterwards (unless you move the check and process into a single check_and_process method...which you can totally do but again the idea is to not require it)
Most languages have a while construct and a do-while.
The while is run as And the do-while switches the order: The issue with the while is that more often than not you need to do some preparations before the condition. So you need to move that to a function, or duplicate it before and inside the loop. Do-while doesn't help, since with that you can't do anything after the condition. The alternative is a while(true) with a condition in the middle. But what if there was a language construct for this? Something like Is there a language that implements this somehow? (I'm sure there is, but I know no one)The best thing is that this construct can be optimized in assembly perfectly: