[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