[swift-evolution] Proposal: Remove the "fallthrough" keyword

Alex Lew alexl.mail+swift at gmail.com
Sun Dec 6 16:12:30 CST 2015


Yes, thanks, Colin -- semantically, I think it's exactly equivalent to a
recursive call to an implicitly defined function closing over the switch.
In practice, the compiler may be able to translate it to a true fallthrough
in many cases.

In any case, I am not arguing for or against reswitch -- I kind of like it,
but also would be fine with keeping fallthrough as is. I just wanted to
better understand what the proposed semantics of reswitch actually were
(hence the var x question, which I guess would be similar to having your
recursive function declare a mutable parameter).

On Sun, Dec 6, 2015 at 4:57 PM, Colin Barrett <colin at springsandstruts.com>
wrote:

> If you need control flow this complex, why not just use recursion?
> reswitch is, near as I can tell, a recursive call to an implicitly defined
> function (closing over the switch).
>
> -Colin
>
> On Dec 6, 2015, at 4:49 PM, Jacopo Andrea Giola <
> swift-evolution at jacopo.giola.org> wrote:
>
> The result is .Two, because you are returning from the reswitch and in
> that case the original x is shadowed by the new execution.
>
> - Jacopo
>
> On 06 Dec 2015, at 22:36, Alex Lew <alexl.mail+swift at gmail.com> wrote:
>
> One question: what is the result of this code?
>
> let x = .One
>
> switch x {
> case .One:
>    reswitch(.Two)
> case .Two:
>    return x
> }
>
> .One or .Two? In other words, is x rebound inside the switch when we
> reswitch?
>
> On Sun, Dec 6, 2015 at 4:28 PM, Alex Lew <alexl.mail+swift at gmail.com>
> wrote:
>
>> It seems reswitch *should* be useable even in cases that aren't a simple
>> "goto". Or am I missing something?
>>
>> For instance, rewriting the example from earlier:
>>
>> switch op {
>> case let .LOAD_INDIRECT(out, in):
>>     reswitch(.LOAD(out, memory[in]))
>> case let .LOAD(out, in):
>>     setReg(out, in)
>> // ...
>> }
>>
>> or, a switch that calculates whether some number n is in a Lisp-style
>> list of numbers
>>
>> switch lst {
>> case .Cons(let m, _) where m == n:
>>      return true
>> case .Cons(_, let rest):
>>     reswitch(rest)
>> case .Empty:
>>      return false
>> }
>>
>> I like reswitch: in some cases, the compiler could optimize to a
>> fallthrough, and in others, you could actually re-switch. But maybe I'm
>> missing something.
>>
>> On Sun, Dec 6, 2015 at 4:14 PM, Jacopo Andrea Giola via swift-evolution <
>> swift-evolution at swift.org> wrote:
>>
>>> Yes, I’m aware that at this time the reswitch can be abused and maybe
>>> can be better refined to disallow such cases.
>>>
>>> Checking the case statement is not a problem by itself, but can be a
>>> problem if is coupled with a where clause that is not true when you
>>> fallthrought.
>>>
>>> I’ve written a really bad draft here
>>> https://gist.github.com/JGiola/f735212789bf2f697847
>>> If anyone wants to jump in and elaborate further is welcome. I will try
>>> to stay on par with this thread but I’m really bad at writing so every help
>>> is welcome.
>>>
>>> And if I remember correctly Daniel Jakult was the first one to made this
>>> proposal so if he wants to take on and then made the official proposal has
>>> every right to do so and I will be very glad if my gist can be a first
>>> reference :)
>>>
>>> - Jacopo
>>>
>>> On 06 Dec 2015, at 21:52, Colin Barrett < colin at springsandstruts.com>
>>> wrote:
>>>
>>> Apologies, Jacopo, for missing the updated proposal, and thank you for
>>> your patience in summarizing it again.
>>>
>>> I’ve only glanced through it but my concern here is that it introduces a
>>> whole class of new and creative “foot-guns" :) In particular, it allows
>>> this construction to loop arbitrarily and creatively, particularly in the
>>> case of associated values.
>>>
>>> I’m not sure why not checking the case statement is considered a problem
>>> for the fallthrough keyword. Assuming it’s impossible to fallthrough to a
>>> case that introduces binders (what would they be bound to?), and that this
>>> is statically checked (both of which seem reasonable assumptions to me,
>>> although if I’m wrong feel free to correct me), isn’t it the entire point
>>> of the fallthrough keyword that it skips checking the case statement? I can
>>> understand how that might be somewhat confusing (and perhaps it should be
>>> documented less prominently) but I’m not sure how it’s a *problem*,
>>> exactly...
>>>
>>> I think I’m still on the side of keeping fallthrough. What’s the
>>> downside of doing nothing? For instance in the case of ++ and -- those
>>> features complicate the design of a numerics library.
>>>
>>> Thanks,
>>> -Colin
>>>
>>> On Dec 6, 2015, at 3:06 PM, Jacopo Andrea Giola <
>>> swift-evolution at jacopo.giola.org> wrote:
>>>
>>>  Hi Colin,
>>>
>>> the initial proposal was indeed to remove entirely the `fallthrough`
>>> keyword but many people expressed your similar concern and from that point
>>> the discussion was steered through an "enhancement" and better refinement
>>> of the keyword.
>>>
>>> The new idea is to substitute the old keyword with "reswitch" passing
>>> the desired new value on which the switch is applied.
>>> So something like this:
>>>
>>> switch (enum) {
>>> case .One:
>>> // do something
>>> reswitch .Two
>>> case .Two:
>>> // do something else
>>> default:
>>> // and so one
>>> }
>>>
>>> This new behaviour, IMO, is better suited for Swift because is more
>>> declarative of the developer intent and doesn't carry over unintentional
>>> misbehaviour.
>>> Is more declarative because you are forced to state in which case you
>>> want to go, and even if the order of the switch’ cases will change in the
>>> future, you don't fall in the wrong case by mistake.
>>>
>>> switch (enum) {
>>> case .One:
>>> // do something
>>> reswitch .Two
>>> case .OneAndAHalf
>>> // maybe this change is not made by you but by a messed up merge
>>> case .Two:
>>> // do something else
>>> default:
>>> // and so one
>>> }
>>>
>>> In this case if you are using the fallthrough keyboard your code is now
>>> broken by accident, and depending on what are you trying to do inside the
>>> cases you can have a hidden bug that your tests are not seeing right away.
>>>
>>> Another advantage is that in this way you can made more
>>> cases fallthrough in the same one even if they are not one over each other
>>>
>>> switch (enum) {
>>> case .One:
>>> // do something
>>> reswitch .Two
>>> case .OneAndAHalf
>>> // so something that you don’t want to do for .One
>>> reswitch .Two
>>> case .Two:
>>> // do something else that you may want to do for .One and .Two
>>> default:
>>> // and so one
>>> }
>>>
>>> I must say that this is a side effect that can be used to messed up the
>>> code flow in a way that is not intended, but is a new behaviour that gives
>>> more power to the switch statement.
>>>
>>> The reswitch keyword in addition is not a mere fallthrough on the new
>>> case without doing the optional checking attached to it, but is intended to
>>> be a new call and all the check are executed.
>>>
>>> switch (enum) {
>>> case .One:
>>> // do something
>>> x = 0;
>>> reswitch .Two
>>> case .OneAndAHalf
>>> // so something that you don’t want to do for .One
>>> reswitch .Two
>>> case .Two where x > 0:
>>> // do something else that you may want to do for .One and .Two
>>> element = array[x]
>>> default:
>>> // and so one
>>> }
>>> (I’m going by memory and by writing this snippets in the mail app
>>> directly, so the code must be incorrect in the syntax and for this I’m
>>> sorry).
>>>
>>> In this case if enum is .One the only case that is executed is case .One
>>> and the code doesn’t fallthrough in the .Two case because we are made the
>>> where invalid by changing the x to a value less than 1.
>>>
>>> Now I don’t remember who was the first one who mede this proposal, and I
>>> don’t know if he is working on a first draft to lay down the things better,
>>> but for me this can be a nice improvement and a neat break with the
>>> C-switch behaviour that Swift has trying to change from the very first beta
>>> disallowing the implicit fallthrough.
>>>
>>> I can be completely wrong but I see the `fallthrough`keyword as a
>>> “temporary” implementation for ease the transition from Obj-C to Swift and
>>> is time to improve it and made the switch statement even more powerful.
>>>
>>> - Jacopo
>>> Sent from my iPad
>>>
>>> On 06 Dec 2015, at 19:57, Colin Barrett via swift-evolution <
>>> swift-evolution at swift.org> wrote:
>>>
>>> tl;dr The fallthrough keyword, as far as I am aware, isn’t costing us
>>> anything; and has at least minimal utility, as I try to demonstrate.
>>>
>>> Apologies for jumping into this thread at an awkward point, but I’ve
>>> only just now subscribed to this list.
>>>
>>> I think the fallthrough keyword is useful in certain circumstances. I’ve
>>> also yet to see an example of where it creates a negative impact, either in
>>> code, optimization, or what have you. Other than “It’s like something in C,
>>> and C is old and busted” I’m unsure of the rationale for removing it. (Feel
>>> free to point me in the right direction.)
>>>
>>> Consider the Planet enum from the documentation. One of the simplest way
>>> to define the number of a planet (i.e. its 1-based index in the ordering of
>>> planets wrt. distance from the sun) is using a switch and fall-through:
>>>
>>> https://gist.github.com/cbarrett/23b24a9fe76efdf006df
>>>
>>> This technique is very extensible — for instance imagine computing the
>>> force induced by the gravity of the other planets on a particular planet.
>>> All that would need to change is the case statements.
>>>
>>> Yes, you could write this by putting the planets into a list and mapping
>>> or folding (or looping) over that, but unless the compiler can “unroll”
>>> that construct, you’re paying for an allocation simply bc of your choice of
>>> control flow. But in fact, you could imagine generalizing this construct
>>> into the implementation of fold for the Planet type — low-overhead folds
>>> for monomorphic types seems like a pretty compelling an natural use case
>>> for fallthrough to me.
>>>
>>> Thanks,
>>> -Colin
>>>
>>> On Dec 6, 2015, at 4:52 AM, Jacopo Andrea Giola via swift-evolution <
>>> swift-evolution at swift.org> wrote:
>>>
>>> +1 for this idea, but I will prefer the reswitch keyword instead of
>>> overloading continue with a new syntax.
>>>
>>> If this proposal is accepted, it must be coupled with a compiler check
>>> that the reswitch statements don't introduce an infinite "switch" loop.
>>>
>>> Sent from my iPad
>>>
>>> On 06 Dec 2015, at 00:23, Steve Canon via swift-evolution <
>>> swift-evolution at swift.org> wrote:
>>>
>>> Very much thinking out loud and not really the implications, I wonder if
>>> we might just use "continue" instead of "reswitch".
>>>
>>> I very much like specifying what case to fall through into, no matter
>>> how we spell it.
>>>
>>> - Steve
>>>
>>> On Dec 5, 2015, at 4:45 PM, John McCall via swift-evolution <
>>> swift-evolution at swift.org> wrote:
>>>
>>> On Dec 5, 2015, at 1:31 PM, John McCall via swift-evolution <
>>> swift-evolution at swift.org> wrote:
>>>
>>> On Dec 4, 2015, at 11:37 PM, John Calsbeek <
>>> john.calsbeek+lists at gmail.com> wrote:
>>> `fallthrough` is conceptually similar to `goto` in that both allow
>>> natural expression of concepts that exist at the instruction level but are
>>> otherwise difficult to express with nested control structures.
>>> `fallthrough` is perhaps slightly less objectionable because control flow
>>> remains local, but it has a similar role.
>>>
>>> It is not particularly natural to write `switch` statements with
>>> `fallthrough` in the reverse order that can be seen in Duff’s Device and
>>> similar constructs (case 7 falls through to 6 which falls through to 5,
>>> etc.). It’s just because you know for certain that all the code in case 6
>>> would be duplicated in case 7, so 7 can transfer into 6 without a jump
>>> instruction. Communicating that to the compiler without `fallthrough`
>>> requires deeply nested `if`s.
>>>
>>>
>>> Right.  One idea that I’ve always had for “fallthrough” is that we might
>>> parameterize it in the future; parameterized it would mean “repeat the
>>> switch with this new value”, so that unparameterized fallthrough would mean
>>> “repeat the switch with a notional value that ends up in the next case”.
>>> There’s a very common pattern in switches of deferring to another case that
>>> I’ve always found very awkward to write in C, and while sometimes there’s
>>> no choice but to extract a helper function, there’s a
>>> still-fairly-structural code pattern here that I think we can sensibly
>>> support.
>>>
>>> On the other hand, there’s an argument that this is an inappropriate
>>> extension for “fallthrough” specifically, which is one reason we’ve never
>>> pursued it.
>>>
>>>
>>> Oh, I see that Joe already brought this up, spelled “reswitch”.
>>>
>>> John.
>>>
>>>
>>> John.
>>>
>>>
>>> One defense comes to mind: there is talk of Swift aiming at systems
>>> programming. Is writing a threaded interpreter loop within the potential
>>> scope of Swift? That’s a use case that could make use of both `fallthrough`
>>> and `goto` (computed goto, really).
>>>
>>> switch op {
>>> case LOAD_INDIRECT:
>>>    in0 = memory[in1]
>>>    fallthrough
>>> case LOAD:
>>>    out0 = memory[in0]
>>> //...
>>> }
>>>
>>> I am personally interested in the prospect of a language that can scale
>>> up to high-level concepts and down to “portable assembler,” but I don’t
>>> know if that is the right direction for Swift’s evolution.
>>>
>>> Cheers,
>>> John
>>>
>>> On Dec 4, 2015, at 2:42 PM, John McCall < rjmccall at apple.com> wrote:
>>>
>>> On Dec 4, 2015, at 2:33 PM, Kevin Ballard < kevin at sb.org> wrote:
>>> It's not actually Duff's Device. Duff's Device relies on the fact that C
>>> switch statements don't actually introduce a new scope, and so it overlaps
>>> a switch with a do-while loop. This lets it only test the number of bytes
>>> once, to jump into the middle of the loop, and then it switches over to a
>>> while loop that decrements a counter every 8 instructions. Basically, it's
>>> a trick for manual loop unrolling that deals with non-multiple-of-8 counts
>>> efficiently.
>>>
>>>
>>> To be pedantic, C switch statements do introduce a new scope.  What
>>> Duff’s Device exploits is that switch is allowed to jump into (almost)
>>> arbitrary scopes, and cases can appear anywhere recursively inside a
>>> switch.
>>>
>>> But your point that Swift’s switch requires cases to be at the top level
>>> within a switch and thus prevents the use of Duff’s Device is 100% correct.
>>>
>>> John.
>>>
>>>
>>> Steve's code is also an example of manual loop unrolling that deals with
>>> non-multiple-of-8 counts, but it has calculate the number of bytes on every
>>> iteration instead of once. It's a good example of one of the uses of
>>> `fallthrough`, it's just not Duff's Device. It's impossible to use Duff's
>>> Device in Swift.
>>>
>>> -Kevin Ballard
>>>
>>> On Fri, Dec 4, 2015, at 02:16 PM, Greg Titus wrote:
>>>
>>> Streza’s source code is an example of Duff’s Device, which is a big
>>> place where switch fallthrough is arguably the cleanest way to do things
>>> and the reason why I’d personally prefer to keep it as part of the
>>> language.
>>>
>>>
>>> On Dec 4, 2015, at 2:12 PM, Erica Sadun < erica at ericasadun.com> wrote:
>>>
>>> Oh let it die, let it die. Any time I use fallthrough I find myself
>>> re-factoring to stop using it.
>>>
>>> *True fact*: On all of   gist.github.com, there are only 22 gist
>>> results for "fallthrough language:swift".
>>> Half of those are people just testing out the feature. Most of the
>>> remaining ones are just complex cases:
>>> *case .Enum1, .Enum2:*
>>> expressed as
>>> *case .Enum1: fallthrough*
>>> *case .Enum2:*
>>>
>>> And then there's streza:
>>> https://gist.github.com/stevestreza/2557dc5ec9e7c694d7ea    I'm pretty
>>> sure that ponies were harmed in the production of whatever that last bit
>>> is.
>>>
>>>
>>>
>>>
>>>
>>> On Dec 4, 2015, at 3:05 PM,   jalkut at red-sweater.com  wrote:
>>>
>>> In the spirit of some other proposals that remove C or C++ style
>>> artifacts, what do folks think about the possibility of removing the
>>> "fallthrough" keyword from the language?
>>>
>>> My understanding is this keyword is only used for the archaic seeming
>>> purpose of perpetuating C-style fallthrough from one switch statement to
>>> the subsequent one. The documentation hedges the use of this keyword in
>>> forbidding terms that make it clear its use is not encouraged. The presence
>>> of the keyword, while an improvement over C’s implicit fallthrough, is a
>>> mark of inelegance on an otherwise well-designed, opinionated
>>> implementation of swtich statements.
>>>
>>> The ugliness of fallthrough’s C-style behavior even demands a caveat in
>>> the documentation:
>>>
>>> "The fallthrough keyword does not check the case conditions for the
>>> switch case that it causes execution to fall into. The fallthrough keyword
>>> simply causes code execution to move directly to the statements inside the
>>> next case (or default case) block, as in C’s standard switch statement
>>> behavior."
>>>
>>> To my mind, the caveat explains just what is wrong with fallthrough,
>>> both in C or Swift: coded that is clearly labeled with deliberate
>>> conditions can nonetheless be reached.
>>>
>>> I quipped about this on Twitter, and the most common pushback I got
>>> seemed to be from people who either did not know about Swift’s support for
>>> comma-separated case statements, or harbored an aesthetic preference for
>>> clustering such cases together with fallthrough statements.
>>>
>>> In my opinion, unless somebody can think of a strong defense for
>>> supporting intentional fallthrough in Swift, removing the keyword would be
>>> a move in the direction of minimizing the language’s complexity while also
>>> discouraging poor coding style in switch statements.
>>>
>>> Thoughts?
>>>
>>> Daniel
>>>
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>
>>>
>>>
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>
>>>
>>>
>>> *_______________________________________________*
>>> swift-evolution mailing list
>>> swift-evolution at swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>
>>>
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>
>>>
>>>  _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>
>>>
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>
>>>
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>
>>>
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>
>>>
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>
>>>
>>>
>>> Untracked with Trackbuster <https://trackbuster.com/?sig>
>>>
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>
>>>
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151206/9d92b0c2/attachment.html>


More information about the swift-evolution mailing list