[swift-evolution] Ad hoc enums / options
Matthew Johnson
matthew at anandabits.com
Tue May 31 15:54:40 CDT 2016
> On May 31, 2016, at 3:46 PM, Vladimir.S <svabox at gmail.com> wrote:
>
> > If you are not allowing callers to store their argument in a variable then
> > I am 100% opposed to this. That would the first case in Swift where you
> > *MUST* provide a literal argument when calling a function, and *CANNOT*
> > provide a value you store in a variable (possibly something you receive as
> > an argument from somewhere else). Why would we want to restrict the
> > flexibility of callers in that way?
>
> Definitely we *must* be able to use a variable in call to function. The problem is how (in case we agreee that the proposed feature could be useful).
>
> I'm thinking about similarity of tuples and this anonymous enums.. If you have tuple in function parameter - how would you use variable to pass it to function? You'll define a variable of the exact same tuple as required, manually, no some separate type provided for this. Yes, if tuple in function definition changed - you'll need to change tuple on caller side:
>
> func foo(int: Int, tuple: (Int, String)) {}
>
> foo(1, tuple: (1, "string"))
>
> var tupleVar : (Int, String) = (1, "string")
>
> foo(1, tuple: tupleVar)
>
> So, why not have the same for such anonymous enums?
>
> func foo(int: Int, variant: (.one | .two)) {}
>
> foo(1, variant: .one)
>
> var enumVar : (.one | .two) = .one
>
> foo(1, variant: enumVar)
>
>
> Seems like consistent solution.
It is consistent with tuples, but using a tuple instead of distinct parameters is usually going to be a bad idea. If we introduce ad-hoc enums people are going to use it frequently. And options like this are the kind of thing that *does* change periodically.
Because those changes are usually additive I’m not too concerned about removing options. But I *am* concerned about re-ordering existing options or adding new options impacting existing variable declarations. For this reason, these would need to be order-independent and support structural subtyping. That way my `(.foo | .bar)` variable is still a valid argument when you change the option list to `(.baz | .bar | .foo)`.
The existing approach of just defining an enum is really not so bad and removes this issue altogether. IMO it is a reasonable “workaround” for now.
I believe there is a lot of overlap between doing this the right way and introducing structural unions like those in Ceylon (fortunately there seems to be growing support for this). For that reason I think it makes sense to wait until we have that feature to look at ad-hoc types with enumerated values like this.
>
>
> On 31.05.2016 22:07, Matthew Johnson via swift-evolution wrote:
>>
>>> On May 31, 2016, at 2:04 PM, Erica Sadun <erica at ericasadun.com <mailto:erica at ericasadun.com>
>>> <mailto:erica at ericasadun.com <mailto:erica at ericasadun.com>>> wrote:
>>>
>>>>
>>>> On May 31, 2016, at 12:35 PM, Matthew Johnson <matthew at anandabits.com <mailto:matthew at anandabits.com>
>>>> <mailto:matthew at anandabits.com <mailto:matthew at anandabits.com>>> wrote:
>>>>
>>>> I think I'm -1 on this. It makes things easier for the implementer of
>>>> the function and harder for the caller.
>>>>
>>>> It's not clear whether the caller could store an argument to pass in a
>>>> variable, but if they could they would need to list out all cases in the
>>>> type of the variable (unless these anonymous enums have structural
>>>> subtyping). This is fragile. Any time that list changes all variable
>>>> declarations will have to be updated.
>>>>
>>>> Functions are implemented once and usually called more many times. It's
>>>> better for callers if you just write it like this:
>>>>
>>>> enum FitOrFill { case fit, fill }
>>>> func scaleAndCropImage(
>>>> image: UIImage,
>>>> toSize size: CGSize,
>>>> *operation: FitOrFill = .fit*
>>>> ) -> UIImage {
>>>>
>>>>
>>>> So unless these anonymous enums are structurally subtyped I think it's a
>>>> bad idea. And introducing structural subtyping here seems like a pretty
>>>> large hammer for this use case.
>>>
>>>
>>> From the caller's point of view, the type must be inferable and exactly
>>> match a token listed in the declaration (which would also appear in Quick
>>> Help):
>>>
>>> let _ = scaleAndCropImage(image: myImage, toSize: size, operation: .fill)
>>>
>>> You would not be able to assign `.fill` to a variable and use that for
>>> the operation value.
>>
>> If you are not allowing callers to store their argument in a variable then
>> I am 100% opposed to this. That would the first case in Swift where you
>> *MUST* provide a literal argument when calling a function, and *CANNOT*
>> provide a value you store in a variable (possibly something you receive as
>> an argument from somewhere else). Why would we want to restrict the
>> flexibility of callers in that way?
>>
>>>
>>> -- E
>>
>>
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160531/4ba758a7/attachment.html>
More information about the swift-evolution
mailing list