[swift-evolution] Proposal: Remove the "fallthrough" keyword
Alex Lew
alexl.mail+swift at gmail.com
Mon Dec 7 14:59:19 CST 2015
I like the idea of a mechanism for tail-call recursion, but agree with
Colin that it's a little strange to hide it behind keywords like "switch"
and "reswtich" -- it makes it less discoverable.
For example, it seems like reswitch, if implemented, would become the only
way to do "recursive" anonymous functions (closures):
// calculate the factorial of each item in the list
[5, 7, 6].map {
switch ($0, 1) {
case (0, let n):
return n
case let (n, m):
reswitch (n-1, m * n);
}
}
(Or am I missing something?) I don't feel strongly either way about this
feature -- I do think it'd be neat to have -- but it would not be entirely
obvious to someone wondering "how would I create a 'recursive' closure for
factorial" that they should turn to switch statements.
On Mon, Dec 7, 2015 at 3:38 PM, Colin Barrett via swift-evolution <
swift-evolution at swift.org> wrote:
>
> On Dec 7, 2015, at 8:55 AM, Joe Groff < jgroff at apple.com> wrote:
>
>
> On Dec 6, 2015, at 1: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.
>
>
> Infinite reswitch loops seem useful. I'm thinking in particular of
> interpreter loops, where it's common to use GCC's computed goto extension
> when written in C.
>
>
> I agree that they have useful semantics; I just wonder if it’s more clear
> to have explicit recursion (with TCO ;) rather than to add a looping
> construct that effectively does the same thing...
>
> Can’t lie though, given the lack of TCO in Swift, a keyword like this
> would probably mean fewer stack frames in code I’ve written myself (for
> instance, a parser combinator library).
>
> -Colin
>
> 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
>
>
>
> _______________________________________________
> 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/20151207/a5d7c553/attachment.html>
More information about the swift-evolution
mailing list