Now that Go 1 has been officially released, I think it is safe to make
a rather radical suggestion regarding the Go switch statement.
{snip}
Now, what problem am I trying to solve here? It would seem reasonable,
at the end of each case section, to be able to determine not just that
we can continue with the next section in linear sequence, but rather
to select, possibly dynamically, which section should be selected,
with the default, as is the case in Go, to drop right out.
{snip}
And, yes, I think Go 2 could look at consolidating for, if, switch and
select into a single paradigm, building both on Dijkstra's work and
Go's extremely clever and pragmatic initialisations. I certainly don't
expect Go 1 to change so dramatically.
Lucio.
On Mar 30, 2012, at 12:22 PM, lucio <lucio...@gmail.com> wrote:
> (short of a GO TO? I don't even want to contemplate that option)
And yet all you're doing is designing a more complex way of doing a goto ;). Goto isn't actually as bad as people seem to think. Like any feature, it can and has been abused, but there are also correct uses.
You used to be able to put labels in a switch and jump between them with goto. However, that was removed when jumping into nested or parallel blocks was outlawed (rightfully so, imo, since it often indicates a bad code structure). You can only jump within a block or into containing blocks now. I personally think jumping between cases within a switch block is one of the better and easier to reason about uses of goto though, since the cases are by default mutually exclusive.
Anyways, you can restart a switch by labeling it and jumping to the label. The idea has occurred to me that perhaps a continue statement for switches would be useful so you can keep checking subsequent conditions without having to go through all the conditions you've already checked and invalidating them somehow. It would also make continue symmetric with break since right now break operates on the switch while continue operates on a containing loop, but that would be a breaking change so it's not going to happen.
Here is an example (using "while" as a name) from EWD's predicate transformer semantics (also with a direct lineage to SNOBOL):func gcd(a, b int) int {while {a < b: b = b - aa > b: a = a - b}return a}this is certainly prettier than any way of expressing it in C, C++, Java, or Go.
Once you accept that the construct needs to be self-consistent, you do
need a different approach. But I also think that the Go technique of
merging initialisation into the construct is very clever and deserves
to be applied here. Also, Dijkstra could not have envisaged the idea
of including in the header the target to be met, as is done in the Go
switch statement, a boolean guard statement is plenty, but Go's
approach is much richer.
So, to continue the discussion, I'd say that the command may well be
named "do" in honour of Dijkstra's original design; that it should
resemble a looping switch, specially regarding its header, where local
variables may be initialised and the nature of the target to be
matched can be described.
Somehow I'm hoping that someone will address two issues I haven't yet
found a solution to yet. The first is obvious from current
discussion: there needs to be an additional component to each guard
that can be used to select that particular section as a possible
target from another section. This could be explicit in the guard
itself, but then we add an overhead that looks ugly, is prone to error
and is onerous for the programmer; we could label each section, but
that is monstrous; so we need something really clever, or just a
different representation for non-linear flow.
The other is what I call the "search quandary", where on completion of
a loop you need another test to figure out which of two outcomes
caused the loop to terminate (e.g.: did you run off the end of the
list, or did you actually find the wanted value in the list?). Using
a looping construct that allows selection of the next section to test
and by trivial extension provides sections that on completion cause
the loop to terminate, we can represent a search operation in a single
construct, a construct that will hopefully cover many less elegantly
expressed tasks.
I hope I'm not being unduly arrogant in suggesting that it is in a new
language like Go that such a construct is most likely to appear. I do
believe that there is scope for discussion and that the evolution of
Go, guided by experienced and competent designers, has created fertile
ground for the invention of a construct I myself still don't entirely
grasp. It appeals to me that the end result is likely to be a
simplifying construct: it may be hard to design and implement, but if
it isn't easier to use and understand, it will serve no purpose. My
belief is that it will be both of these.
Lucio.
The reality is that in either model, we are constrained by the linear
nature of the representation of computer programs to one single
possibility: you either drop into the next section or you don't.
Which means that if you have a single situation that can be
represented in this fashion, you win, but the moment, say, two
distinct case sections should both continue into the same third case
section, there is no mechanism (short of a GO TO? I don't even want
to contemplate that option) that makes this possible. It is even more
serious when there are a few such situations within the same switch.
Now, what problem am I trying to solve here? It would seem reasonable,
at the end of each case section, to be able to determine not just that
we can continue with the next section in linear sequence, but rather
to select, possibly dynamically, which section should be selected,
with the default, as is the case in Go, to drop right out.
For small logical constructs this kind of complexity doesn't seem to give overwhelming readability/writability improvement (we're not even discussing performance of the code generated from it, it's probably not relevant).
Something like this, where every "case" is evaluated in order and execution can be terminated with break or restarted with continue.
If {
case A == true:
//do something
If someCheck() { break; } // this breaks out of the switch
case SomeOtherCheck():
continue // this is a goto jump back to the start of the if block
}
But in my opinion there ought to be a visibly distinguishable
construct where order is not obeyed, but the relationship between
sections is stated explicitly and possibly (preferably) dynamically.
And this does resemble implementing a state machine in the language,
which some have stated is a bad idea, but seems to me, if done
properly, to be an asset.
Anyway, I'm happy to discuss this idea with somebody who clearly
understands the issues better than I do, I make no apology for not
having an adequate theoretical background, I just promise to listen
attentively enough to learn something from it :-)
Lucio.
Your note, however, is very illuminating and I really thank you for
that, I guess this is very much what I was looking forward to, without
necessarily knowing it. I do feel a little awed by the interest, and
pleased that I am not so ill informed as to voice totally inane
opinions. As I mentioned, my theoretical knowledge is not very sound.
Regarding the "default" clause, it seems helpful to me to be able to
summarise all exceptions under one heading, but one must keep in mind
that in Dijkstra's model failure to meet at least one guard condition
was the sole mechanism to exit the do construct. As you mentioned,
introducing a default also forces the addition of a break command
(consistent with Go, but not with Dijkstra's design), I'm not sure
about continue, but there would be cause to bring that in as well, I'm
sure.
I thought I had already considered these - I voted for a default
without realising the consequences - but now it is not so clear
anymore. I'll need to spend more time on that, but I confess you have
done a lot better than I in the last few exchanges. To answer your
question, though, at the very least default would terminate the
repetition, in my opinion, providing the escape route I'm looking for
in the "search quandary", but not quite fulfilling all the
requirements.
It seems to me that a complete design would include instructions at
each section exit to navigate within the loop or to terminate,
basically a layer of instructions in some way orthogonal to the
guards. I guess break and continue always provided a blunt version of
what I'm now hoping to refine. The difficulty, of course, is to
provide a tool that is not so sharp the programmer lands up losing a
finger or two to it. But the discussion so far does suggest looking
for two textures and being able to blend them or separate them as
required by the problem in hand. Making this a practical construct
will not be easy, possibly not even helpful, but thinking about it
can't possibly be harmful.
Here, as I did in discovering Plan 9 many years ago, I have to thank
the same people for providing a fresh platform for novel thought and
making this type of speculation worthwhile.
It reminds me of the mental shift discovering and using APL caused me.
I have to mention that here, because my esteemed friends from Bell
Labs are no fans of APL (at least insofar as I have been able to
establish from the occasional email exchanges where the subject came
up) and I can't just continually praise them, I have to poke them in
the ribs occasionally, too :-)
Anyway, this discussion has been very good for me, I'm looking forward
to wherever it eventually takes us and I am thankful that it is still
resonating with others. Maybe the time has come to shift it to
private mail, maybe not. There are a few items I would like to see
discussed, although resolution is still outstanding more or less
across the board and bringing these into play will almost certainly
murk the waters even further.
The Go preambles in the if and switch constructs, together with the
extension of the scope of the constructs to the preamble, are a very
clever, "outside the box" invention. I'd like to think that they
ought to apply to a do construct too, but I can't quite visualise how
they would work.
Hm, I thought I had more up my sleeve, but right now this is all that
comes to mind. Looking forward to more input, definitely, hopefully
I'll be able to continue to contribute. As I mentioned, I will not be
disappointed if the discussion does not lead to a Go extension, I have
already gained and learned much from the exchange so far.
Lucio.