[swift-evolution] Ad hoc enums / options
Tony Allevato
allevato at google.com
Wed Jun 1 17:14:45 CDT 2016
On Wed, Jun 1, 2016 at 3:02 PM Vladimir.S <svabox at gmail.com> wrote:
> > in other words, we could consider allowing this:
> > func foo(bar: (.fit | .fill)) {
> > baz(bar: bar)
> > }
> > func baz(bar: (.fit | .fill | .florp) { ... }
> >
> > In other words, an ad hoc enum T can be used wherever an ad hoc enum U
> is
> > expected if T ⊆ U.
>
> Can't agree with this. Just because the same analogue with tuples :
> differently defined tuples are different types. Tuples with different order
> of types in declaration - are different types. So I expect here instance of
> (.fit | .fill) `bar` is not of the same type as (.fit | .fill | .florp)
>
I would argue that the analogy to tuples doesn't apply in this case. For
tuples, order of the arguments matters, and part of the structural
definition of a tuple is the number of its elements. Neither of those
applies for an ad hoc enum—it is defined solely as a set of named cases.
After writing that, however, that *does* seem like the kind of implicit
conversion that Swift tends to avoid. So maybe an explicit conversion would
better fit the language design.
>
> But +1 to be able to 'convert' instance of (.fit | .fill) to instance of
> (.fit | .fill | .florp). For example(if we'll have init(caseName) and
> .caseName for enums):
>
> func foo(bar: (.fit | .fill)) {
> let bazbar = (.fit | .fill | .florp).init(caseName: bar.caseName)
> baz(bar: bazbar)
> }
> func baz(bar: (.fit | .fill | .florp) { ... }
>
I'm not crazy about this because I would expect a conversion that requires
a round-trip transformation of the string case name to be negative for
performance. Why not just:
let bazbar = (.fit | .fill | .florp)(bar)
which the compiler ought to be able to optimize much better?
>
>
> On 02.06.2016 0:38, Tony Allevato wrote:
> > I find myself agreeing with the idea that ad hoc enums are to enums as
> > structs are to tuples. Based on that analogy, why should an ad hoc enum
> > *need* a name (autogenerated or otherwise) any more than a tuple needs a
> > name? Would those who dislike ad hoc enums argue that this also shouldn't
> > be allowed:
> >
> > func foo(bar: (x: Int, y: Int)) {}
> > let t: (x: Int, y: Int) = (x: 5, y: 5)
> >
> > If someone writes `(.fit | .fill)` (or whatever the hypothetical syntax
> > might be), that should just *be* the type the same way that `(x: Int, y:
> > Int)` is a type without a name, and that type can be used in argument
> > lists, variables, or whatever. There shouldn't be any worry about
> > declarations across multiple functions colliding or being incompatible
> any
> > more than we would worry about two functions declaring arguments of type
> > `(x: Int, y: Int)` would collide or be incompatible.
> >
> > One side of ad hoc enums that I'd like to see explored is that, by being
> > unnamed, they're basically anonymous finite sets and we could apply
> > well-defined subset relationships to them: in other words, we could
> > consider allowing this:
> >
> > func foo(bar: (.fit | .fill)) {
> > baz(bar: bar)
> > }
> > func baz(bar: (.fit | .fill | .florp) { ... }
> >
> > In other words, an ad hoc enum T can be used wherever an ad hoc enum U is
> > expected if T ⊆ U.
> >
> >
> > On Wed, Jun 1, 2016 at 1:43 PM L. Mihalkovic via swift-evolution
> > <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
> >
> >
> >
> > > On Jun 1, 2016, at 6:51 PM, Vladimir.S <svabox at gmail.com
> > <mailto:svabox at gmail.com>> wrote:
> > >
> > > Yes, I also can support the idea of autogenerated type name (like
> > Enum_fit_OR_fill) as long as it allows to do all the things we are
> > discussing here: declare (.fit|.fill) in function, use .fit on
> calling
> > side, use (.fit|.fill) to declare temporary variable of type
> compatible
> > with such function parameter etc.
> > >
> >
> > It all works because the compiler is just being a thoughless scribe
> > that just writes the standard enum we don't bother to write
> ourselves.
> > Because the heuristic is simple and straightforward then it is
> > predictible. The enum can be used with its long name be ause it is a
> > real enum. And writing the short form of it also works because the
> > compiler knowns uniquely what the long name is everytime it runs into
> > the short name.
> >
> >
> > > But how do you suggest to define a type of such function in
> > `typealias` for example? i.e. for func my(option: (.fit|.fill) {..}
> > >
> > > typealias MyFunc = ((.fit|.fill)) -> ()
> > > or as
> > >
> > > typealias MyFunc = (Enum_fit_OR_fill) -> ()
> > >
> >
> > Ideally there is no difference whatsoever, there is a single enum, it
> > is produced at the module level, and it has the long form name.
> >
> > There can be rules that would prevent us from doing that with
> > externally visible APIs, if the core team fuges that we should take
> the
> > time to write our enums manually and cleanly to make them visible to
> > the world, but it is not a necessary rule.
> >
> >
> > >
> > > But I still can't support the idea of limiting the usage of such
> > enums - i.e. "To deal with milti site definition, the compiler would
> > simply flag a error/warning, or be silent in the presence of a new
> > annotation:". I really think we need then introduce the same rule for
> > tuples - so no one can use the same tuple declaration in function -
> > they then should declare separate struct type or use @something for
> > such functions. Nobody wants such rule for tuples.
> > >
> >
> > Multi site thing is not a limitation... Is is a proposed rule to say
> > that we are able to be lazy twice without being penalized. Yhe
> compiler
> > does not like when we define the same thing twice, and thse short
> form
> > amount to doing what he does not let us do. But because this is about
> > concise and lazy, then the compiler can let us get away with it if we
> > use an annotation that lets it know that "it is not a mistake.. I
> > really dont want to write that enum myself, even though I am using
> the
> > same abbreviation twice". Otherwise, the compiler would let us know
> > that the second time could be a mistake because there is already
> > something with the same name...
> >
> > But again this is a separate idea from the core notion of a syntax
> > sugaring for writing real enums the lazy (clever) way
> >
> > >> On 01.06.2016 19:04, L. Mihalkovic wrote:
> > >> The only problem with this proposal is to consider them ad-hoc
> > enums... If we view them as having nothing ad-hoc about them and the
> > thing to be a simple sugaring exercise, then I think all the
> opositions
> > on grounds of breaking the language disapear. It still does not mean
> it
> > should be done if the core team does not like the idea of encouraging
> > laziness, or simply do not like what it makes them look like. No
> matter
> > what, this type of sugaring exercise has been clearly stated as out
> of
> > scope for 3.0
> > >>
> > >>>> On Jun 1, 2016, at 2:38 PM, Vladimir.S via swift-evolution
> > <swift-evolution at swift.org <mailto:swift-evolution at swift.org>>
> wrote:
> > >>>>
> > >>>> On 01.06.2016 11:00, Austin Zheng wrote:
> > >>>> Tuples are a structural type, they are described entirely by
> the fact
> > >>>> that they are a tuple, plus their contained types.
> > >>>>
> > >>>> Enum cases are not individual types; that precedent exists
> nowhere in
> > >>>> Swift. You can't (yet) build a structural type out of something
> that
> > >>>> isn't a type. The fact that you had to propose something like
> > >>>> "AdhocEnumFitFill_2383748" as an autogenerated name for the type
> > >>>> demonstrates the proposal's weaknesses: a tuple is an ad-hoc
> type that
> > >>>> describes itself, while an anonymous enum isn't.
> > >>>
> > >>> Yes, I understand the point about the type of such adhoc enum.
> > >>> The only workaround I can see in this case(if we'd really want to
> > have it in language) if adhoc enum type will be `(.Fit|.Fill)` i.e.
> > textual representation if the declared type. As I understand this
> also
> > could not be a solution.. I.e. for example
> > `(Int,String,(.Fit|.Fill))->String`
> > >>>
> > >>> From other point of view, adding such type to typesystem will add
> > some consistence : you can create a function that don't need
> definition
> > of separate structure type(tuple will be used) and don't need
> separate
> > enum type(ad-hoc enum will be used). I.e. all data the function needs
> > to process could be described in function definition. Today we need
> to
> > use ugly Bool flags in case we want to achieve the same target.
> > >>>
> > >>>>
> > >>>> Now if enum cases were equivalent if they had the same name
> (like how
> > >>>> "Int" means the same thing no matter what tuple or generic type
> it is
> > >>>> used in), we'd have a good foundation for a self-describing
> structural
> > >>>> type. But this isn't how the existing named enum types work.
> Why would
> > >>>> it be a good idea to make anonymous enum cases interchangeable
> by
> > name?
> > >>>> Properties on different types aren't interchangeable, even if
> they
> > have
> > >>>> the same type. In fact, no type member that I am aware of is
> > >>>> interchangeable solely on the basis of name. An
> > "ArtistAction.Draw" and
> > >>>> "CowboyAction.Draw" might have the same name, but they mean
> completely
> > >>>> different things.
> > >>>
> > >>> I don't think they should be 'interchangeable by name', but just
> > like tuples if you defined adhoc enum with exactly the same cases as
> > ad-hoc enum in function parameters - then they are of the same type.
> > >>>
> > >>> I.e. :
> > >>>
> > >>> func foo(option: (.fit|.fill)) {..}
> > >>>
> > >>> foo(.fit) // .fit is of type (.fit|.fill) from definition
> > >>>
> > >>> let e : (.fit|.fill) = .fit
> > >>> foo(e) // e is of (.fit|.fill) type, equal to definition
> > >>>
> > >>> but
> > >>>
> > >>> func foo2(option: (.fit|.fill|.other)) {..}
> > >>>
> > >>> foo2(.fit) // ok, here .fit is of (.fit|.fill|.other) type
> > >>> foo2(e) --> Error, e is not of type (.fit|.fill|.other)
> > >>>
> > >>>>
> > >>>> Finally, I have to ask: if you are updating your anonymous enum
> in
> > >>>> multiple places, how much effort have you actually saved over a
> > one-line
> > >>>> enum definition? In fact, tuples are a great example of this:
> best
> > >>>> practices usually state that they are good for ad-hoc
> destructuring,
> > >>>> such as retrieving multiple return values from a function or
> pattern
> > >>>> matching across several values at once, but structs are better
> > used for
> > >>>> almost everything else, since they carry semantic meaning that
> tuples
> > >>>> don't.
> > >>>>
> > >>>
> > >>> Just the same pros and cons for ad-hoc enums vs enum declaration
> as
> > for tuples vs struct declaration. Yes can use it with care and you
> can
> > use it in wrong way.
> > >>>
> > >>> Btw, I feel like this could be very handy to return adhoc enum:
> > >>>
> > >>> func something() -> (.one|.two|.three) {...}
> > >>>
> > >>>> I hope that clarifies my thoughts on the matter.
> > >>>>
> > >>>> Best, Austin
> > >>>>
> > >>>>
> > >>>>> On Jun 1, 2016, at 12:36 AM, Vladimir.S <svabox at gmail.com
> > <mailto:svabox at gmail.com>> wrote:
> > >>>>>
> > >>>>> On 01.06.2016 9:55, Austin Zheng via swift-evolution wrote:
> > >>>>>> Maybe it's overkill. My personal opinion is that breaking the
> > >>>>>> symmetry of the language like this (are there any other types
> of
> > >>>>>> function arguments that cannot be passed as either variable
> values
> > >>>>>> or literals?) is too much a price to pay. Your library thinks
> it's
> > >>>>>> being clever and vends its functions as taking anonymous enum
> flags,
> > >>>>>> and now there are a bunch of things I can't do with those
> functions
> > >>>>>> anymore.
> > >>>>>>
> > >>>>>> A regular enum can be declared in one line anyways:
> > >>>>>>
> > >>>>>> enum ScaleCropMode { case Fit, Fill }
> > >>>>>
> > >>>>> Why do we have tuples? Struct could be defined by one line
> `struct
> > >>>>> SomeValue { var x = 0, y = 0 }` ;-) I.e. from my point of view
> > >>>>> developer should decide what he/she wants to use: ad-hoc enum
> or
> > >>>>> defined enum type *exactly* as now he/she can decide to use
> the same
> > >>>>> tuples in multiply functions instead of one defined struct
> type.
> > >>>>>
> > >>>>> I replied regarding the variable on other message. (In short:
> I think
> > >>>>> of the same principle as for tuples: you can declare variable
> `let e:
> > >>>>> (.fill | .fit) = .fill` and use it)
> > >>>>>
> > >>>>>>
> > >>>>>> Austin
> > >>>>>>
> > >>>>>>> On May 31, 2016, at 11:44 PM, Charles Constant
> > >>>>>>> <charles at charlesism.com <mailto:charles at charlesism.com>
> > <mailto:charles at charlesism.com <mailto:charles at charlesism.com>>>
> wrote:
> > >>>>>>>
> > >>>>>>>> It breaks the ability to pass in a variable containing the
> > >>>>>>>> desired
> > >>>>>>> value, rather than the literal value itself.
> > >>>>>>>
> > >>>>>>> Maybe that's appropriate? If the caller is not passing in a
> > >>>>>>> hardcoded enum case, then that enum is probably general
> enough
> > >>>>>>> that it warrants a normal enum. But there are also situations
> > >>>>>>> where the same function is called from several files in the
> same
> > >>>>>>> code-base with different flags. Those are situations where it
> > >>>>>>> feels like overkill to clutter up my codebase with separate
> enums,
> > >>>>>>> only used by a single function.
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> On Tue, May 31, 2016 at 9:24 PM, Austin Zheng via
> swift-evolution
> > >>>>>>> <swift-evolution at swift.org <mailto:swift-evolution at swift.org
> >
> > <mailto:swift-evolution at swift.org <mailto:swift-evolution at swift.org
> >>>
> > >>>>>>> wrote:
> > >>>>>>>
> > >>>>>>> I admire the desire of this proposal to increase the
> readability
> > >>>>>>> of code. I'm -1 to the proposal itself, though:
> > >>>>>>>
> > >>>>>>> - It breaks the ability to pass in a variable containing the
> > >>>>>>> desired value, rather than the literal value itself. (Unless
> you
> > >>>>>>> actually want a not-so-anonymous enum type whose definition
> > >>>>>>> happens to live in a function signature rather than somewhere
> > >>>>>>> you'd usually expect a type definition to live.) - It breaks
> the
> > >>>>>>> ability to store a reference to the function in a variable of
> > >>>>>>> function type (ditto). - Almost every time I've wanted to
> use one
> > >>>>>>> of these "anonymous enums" in my code, I've ended up needing
> to
> > >>>>>>> use that same enum elsewhere. In my experience, 'lightweight
> > >>>>>>> enums' don't end up saving much time compared to a
> full-fledged
> > >>>>>>> one.
> > >>>>>>>
> > >>>>>>> Like Brent said, I have to say no to any proposal that tries
> to
> > >>>>>>> make enums synonyms for numerical values. What happens if you
> > >>>>>>> rearrange your anonymous enum cases between library
> versions? Do
> > >>>>>>> you somehow store an opaque case-to-UInt8 table somewhere for
> > >>>>>>> every anonymous enum you define for resilience? What happens
> when
> > >>>>>>> people start bringing back terrible C patterns, like doing
> > >>>>>>> arithmetic or bitwise ops on the underlying case values? At
> least
> > >>>>>>> you have to try pretty hard as it is to abuse Swift's enums.
> > >>>>>>>
> > >>>>>>> Austin
> > >>>>>>>
> > >>>>>>> On Tue, May 31, 2016 at 8:25 PM, Brent Royal-Gordon via
> > >>>>>>> swift-evolution <swift-evolution at swift.org
> > <mailto:swift-evolution at swift.org>
> > >>>>>>> <mailto:swift-evolution at swift.org
> > <mailto:swift-evolution at swift.org>>> wrote:
> > >>>>>>>
> > >>>>>>>> And the obvious answer is you can have up to 255 of these
> babies
> > >>>>>>>> for the anonymous enum type, and be able to pass numerical
> > >>>>>>>> equivalents UInt8 with compile time substitution. That the
> > >>>>>>>> ad-hoc enumeration is basically a syntactic shorthand for
> UInt8,
> > >>>>>>>> with an enforced upper bound compile time check simplifies
> > >>>>>>>> everything including switch statements.
> > >>>>>>>
> > >>>>>>> If I wanted a language like that, I'd be writing C, not
> Swift.
> > >>>>>>>
> > >>>>>>> -- Brent Royal-Gordon Architechies
> > >>>>>>>
> > >>>>>>> _______________________________________________
> swift-evolution
> > >>>>>>> mailing list swift-evolution at swift.org
> > <mailto:swift-evolution at swift.org>
> > >>>>>>> <mailto:swift-evolution at swift.org
> > <mailto:swift-evolution at swift.org>>
> > >>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> _______________________________________________
> swift-evolution
> > >>>>>>> mailing list swift-evolution at swift.org
> > <mailto:swift-evolution at swift.org>
> > >>>>>>> <mailto:swift-evolution at swift.org
> > <mailto:swift-evolution at swift.org>>
> > >>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
> > >>>>>>>
> > >>>>>>>
> > >>>>>>
> > >>>>>>
> > >>>>>>
> > >>>>>> _______________________________________________
> swift-evolution
> > >>>>>> mailing list swift-evolution at swift.org
> > <mailto:swift-evolution at swift.org>
> > >>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
> > >>>>>>
> > >>>>
> > >>>>
> > >>> _______________________________________________
> > >>> swift-evolution mailing list
> > >>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
> > >>> https://lists.swift.org/mailman/listinfo/swift-evolution
> > >>
> > _______________________________________________
> > swift-evolution mailing list
> > swift-evolution at swift.org <mailto: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/20160601/31d15cba/attachment-0001.html>
More information about the swift-evolution
mailing list