Ad hoc enums / options

Unions have been discussed earlier in this group and I personally
think this is an issue better solved using function overloading.
Despite this, I see how union types could be implemented (hint:
Optionals) but to use it in code would require you to, at least, test
for the type of the value at hand for the blocks of different code
between types. It feels like trying to bend a static typed language to
work a bit like a dynamic typed and while both have their pros and
cons I don't really think there is any benefit for the programmer and
the readability of the code in bending the type checker like this.

Unions are a specialized tool that should be used carefully and precisely. That said, I have been uncovering several use cases where they are *exactly* what is needed. Without them you end up with boilerplate of one kind or another.

···

Sent from my iPad

On Jun 1, 2016, at 6:35 AM, Leonardo Pessoa via swift-evolution <swift-evolution@swift.org> wrote:

L

On 1 June 2016 at 08:06, Haravikk via swift-evolution > <swift-evolution@swift.org> wrote:

I agree the second is much nicer, and a lot clearer on what each of the
options does; fitImage: true is pretty clear, but fitImage: false is not,
but the ad-hoc enum is clear on both counts. That said, the questions of
interoperability are a big issue for ad-hoc enums, as either they’re too
strict which becomes inconvenient (a .Fit | .Fill working with one method
but not another) or too relaxed to be safe. Of course, in the latter case
you’re replacing a Bool, which couldn’t be more relaxed in terms of where it
accepts values from.

Still, I think in this case it would be better to fully-define an enum, as
it gives you total control over compatibility and reusability of the type,
which you can’t really with the ad-hoc form without making it overly
complex.

The main type of ad-hoc enum I want to see is a union-type like so:

func someMethod(value:(Int | String)) { … }

This would basically be an ad-hoc enum where each case identifies one of the
possible types, and the value bound as that type. This works however because
there’s no ambiguity in the meaning; an (Int | String) is the same wherever
you use it, whereas a general-purpose ad-hoc enum is less clear, as an other
method might also take .Fit and .Fill values, but these may have a slightly
different meaning.

So yeah, I like the idea in principle, but I think in practice it has too
many headaches to overcome for it to be as simple as it first appears =(

On 31 May 2016, at 17:16, Erica Sadun via swift-evolution >> <swift-evolution@swift.org> wrote:

Here's a function signature from some code from today:

func scaleAndCropImage(
image: UIImage,
toSize size: CGSize,
fitImage: Bool = true
) -> UIImage {

And here's what I want the function signature to actually look like:

func scaleAndCropImage(
image: UIImage,
toSize size: CGSize,
operation: (.Fit | .Fill) = .Fit
) -> UIImage {

where I don't have to establish a separate enumeration to include ad-hoc
enumeration-like semantics for the call. A while back, Yong hee Lee
introduced anonymous enumerations (and the possibility of anonymous option
flags) but the discussion rather died.

I'm bringing it up again to see whether there is any general interest in
pursuing this further as I think the second example is more readable,
appropriate, and Swifty than the first, provides better semantics, and is
more self documenting.

Thanks for your feedback,

-- Erica

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Unions have been discussed earlier in this group and I personally
think this is an issue better solved using function overloading.
Despite this, I see how union types could be implemented (hint:
Optionals) but to use it in code would require you to, at least, test
for the type of the value at hand for the blocks of different code
between types. It feels like trying to bend a static typed language to
work a bit like a dynamic typed and while both have their pros and
cons I don't really think there is any benefit for the programmer and
the readability of the code in bending the type checker like this.

L

···

On 1 June 2016 at 08:06, Haravikk via swift-evolution <swift-evolution@swift.org> wrote:

I agree the second is much nicer, and a lot clearer on what each of the
options does; fitImage: true is pretty clear, but fitImage: false is not,
but the ad-hoc enum is clear on both counts. That said, the questions of
interoperability are a big issue for ad-hoc enums, as either they’re too
strict which becomes inconvenient (a .Fit | .Fill working with one method
but not another) or too relaxed to be safe. Of course, in the latter case
you’re replacing a Bool, which couldn’t be more relaxed in terms of where it
accepts values from.

Still, I think in this case it would be better to fully-define an enum, as
it gives you total control over compatibility and reusability of the type,
which you can’t really with the ad-hoc form without making it overly
complex.

The main type of ad-hoc enum I want to see is a union-type like so:

func someMethod(value:(Int | String)) { … }

This would basically be an ad-hoc enum where each case identifies one of the
possible types, and the value bound as that type. This works however because
there’s no ambiguity in the meaning; an (Int | String) is the same wherever
you use it, whereas a general-purpose ad-hoc enum is less clear, as an other
method might also take .Fit and .Fill values, but these may have a slightly
different meaning.

So yeah, I like the idea in principle, but I think in practice it has too
many headaches to overcome for it to be as simple as it first appears =(

On 31 May 2016, at 17:16, Erica Sadun via swift-evolution > <swift-evolution@swift.org> wrote:

Here's a function signature from some code from today:

func scaleAndCropImage(
image: UIImage,
toSize size: CGSize,
fitImage: Bool = true
) -> UIImage {

And here's what I want the function signature to actually look like:

func scaleAndCropImage(
image: UIImage,
toSize size: CGSize,
operation: (.Fit | .Fill) = .Fit
) -> UIImage {

where I don't have to establish a separate enumeration to include ad-hoc
enumeration-like semantics for the call. A while back, Yong hee Lee
introduced anonymous enumerations (and the possibility of anonymous option
flags) but the discussion rather died.

I'm bringing it up again to see whether there is any general interest in
pursuing this further as I think the second example is more readable,
appropriate, and Swifty than the first, provides better semantics, and is
more self documenting.

Thanks for your feedback,

-- Erica

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Sorry, my intention wasn’t to debate them, I was just using them as an example of a specialised ad-hoc enum where compatibility isn’t an issue (because a union of the same types means the same thing everywhere you use it, which isn’t the case for general ad-hoc enums).

···

On 1 Jun 2016, at 12:35, Leonardo Pessoa <me@lmpessoa.com> wrote:

Unions have been discussed earlier in this group and I personally
think this is an issue better solved using function overloading.

I support the original proposal. My assumption is that (.fit|.fill) is the
name of a type that can be used anywhere types can be named.

I think the concern about duplicates is misplaced. If the same developer
creates the scaleAndCrop function and the rect function, they may decide to
extract the enum type to a named enum when they see the second use. If they
don't, it's because they're in the flow - no harm results from naming this
type in two places. They have the opportunity to reconsider their decision
if they add cases later.

Ad hoc enums are to named enums as closures are to funcs: closures and ad
hoc enums both increase developer flow at the risk that the developer needs
to refactor later to maximize reuse and minimize duplication. Allowing
developers to make these trade-offs according to their own preference is a
good thing.

-- Callionica

···

On Tue, May 31, 2016 at 2:20 PM, Brent Royal-Gordon via swift-evolution < swift-evolution@swift.org> wrote:

> func scaleAndCropImage(
> image: UIImage,
> toSize size: CGSize,
> operation: (.Fit | .Fill) = .Fit
> ) -> UIImage {

As I said the last time this proposal came up, I think this is great right
up until the moment you need `operation` to be computed or kept in a
variable. Then you need to start copying your anonymous enum type all over
your source, and there's no central place to make changes. The same thing
is true of tuples, but tuples are easy to structure and destructure from
individual values on the spot; anonymous enums aren't really like that.

And this problem starts occurring *very* quickly. I mean, you've left
`scaleAndCropImage`'s implementation out. Imagine implementing it with a
couple helper functions, and you start to see this problem occurring:

        func scaleAndCrop(image: UIImage, to size: CGSize, operation:
(.fit | .fill) = .fit) -> UIImage {
                let drawingRect = rect(of: size, for: operation)
                return drawnImage(image, in: drawingRect)
        }

        private func rect(of size: CGSize, for operation: (.fit | .fill))
-> CGRect {

Already we have one duplication; if we add .fillWidth and .fillHeight
modes, we'll need to change signatures in two places.

In short, when you dig into this proposal and start thinking of use cases
that are even slightly less than completely trivial, I think the case for
it falls apart.

(It's also worth noting that this isn't suitable for options, because it
creates an anonymous enum, not an anonymous option set.)

--
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I agree the second is much nicer, and a lot clearer on what each of the options does; fitImage: true is pretty clear, but fitImage: false is not, but the ad-hoc enum is clear on both counts. That said, the questions of interoperability are a big issue for ad-hoc enums, as either they’re too strict which becomes inconvenient (a .Fit | .Fill working with one method but not another) or too relaxed to be safe. Of course, in the latter case you’re replacing a Bool, which couldn’t be more relaxed in terms of where it accepts values from.

Still, I think in this case it would be better to fully-define an enum, as it gives you total control over compatibility and reusability of the type, which you can’t really with the ad-hoc form without making it overly complex.

The main type of ad-hoc enum I want to see is a union-type like so:

  func someMethod(value:(Int | String)) { … }

This would basically be an ad-hoc enum where each case identifies one of the possible types, and the value bound as that type. This works however because there’s no ambiguity in the meaning; an (Int | String) is the same wherever you use it, whereas a general-purpose ad-hoc enum is less clear, as an other method might also take .Fit and .Fill values, but these may have a slightly different meaning.

So yeah, I like the idea in principle, but I think in practice it has too many headaches to overcome for it to be as simple as it first appears =(

Here's a function signature from some code from today:

func scaleAndCropImage(
    image: UIImage,
    toSize size: CGSize,
    fitImage: Bool = true
    ) -> UIImage {

And here's what I want the function signature to actually look like:

func scaleAndCropImage(
    image: UIImage,
    toSize size: CGSize,
    operation: (.Fit | .Fill) = .Fit
    ) -> UIImage {

I think it is a very reasonable proposal that does not violate the language.

Enums are nominal types, so what makes them unique is their names. It means that the name CANNOT be RANDOMLY generated... But it does not mean that the name cannot be meaningfully generated... So it is perfectly reasonable for the compiler to behave like a beginer programmer might and go through a naive but predictable heuristic to derive a semantically meaningful unique name:

Public enum enum_Fit_OR_Fill {
    case Fit
    case Fill
}

The prefix may not even be required. There is no chance that the name would wind up colliding with something done manually, and fixing the declaration to be systematically done at the module level would ensure clear visibility. The method signature would also be clean with "operation" exposed as:
    operation: enum_Fit_OR_Fill

To deal with milti site definition, the compiler would simply flag a error/warning, or be silent in the presence of a new annotation:

@strawman_use_synthesised_enum func scaleAndCropImage(....)

This would indicate that we acknowledge taking full responsibility for avoiding name collisions

To be more defensive, there could be a rule stating that these cannot be exported from modules (basically cannot be API). This is nothing more than a simple exercise of syntax sugaring...

Now having said that, if I recall, chris was clear that sugaring in NOT for 3.0

···

On Jun 1, 2016, at 1:06 PM, Haravikk via swift-evolution <swift-evolution@swift.org> wrote:

On 31 May 2016, at 17:16, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

where I don't have to establish a separate enumeration to include ad-hoc enumeration-like semantics for the call. A while back, Yong hee Lee introduced anonymous enumerations (and the possibility of anonymous option flags) but the discussion rather died.

I'm bringing it up again to see whether there is any general interest in pursuing this further as I think the second example is more readable, appropriate, and Swifty than the first, provides better semantics, and is more self documenting.

Thanks for your feedback,

-- Erica

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

This is my objection to this idea. It does not encourage reuse.

I would not be able to assign to a variable:

let selectedOperation = .fill

In order to then do this later in the program:

scaleAndCropImage(image: myImage, toSize: size, operation: selectedOperation)

···

On May 31, 2016, at 3:04 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

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.

That's a big negative point. This means that a small convenience for the implementor results in heavy restrictions for the caller who cannot structure his algorithm appropriately and will probably have to create (i.e. duplicate) the enum anyway.
Thinking of your example: where might the value for .fit or .fill come from? In most cases it won't be hardcoded in the call, but be either the result of a user setting or an algorithm. Both would need to be able to assign this value.

As a consequence this is just a feature for use in a Playground where it is very convenient, but that means it doesn't pull its own weight, because it degrades the design outside of Playgrounds.
So a -1 from me.

-Thorsten

-Thorsten

···

Am 31.05.2016 um 21:04 schrieb Erica Sadun via swift-evolution <swift-evolution@swift.org>:

On May 31, 2016, at 12:35 PM, Matthew Johnson <matthew@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.

Here is a correction to the equivalent declaration. It would be a RawRepresentable String enum to be compatible with serialization mechanisms e.g. JSON. and other representations. Again, the name could be auto-generated to keep the syntax succinct.

would be equivalent to

class MyImage {
   enum ScaleCropFitFill : String {
    case Fit
    case Fill
  }
...

···

On May 31, 2016, at 12:25 PM, Christopher Kornher <ckornher@me.com> wrote:

Apologies for using you as a relay...

Begin forwarded message:

From: Charlie Monroe via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>
Subject: Re: [swift-evolution] Ad hoc enums / options
Date: May 31, 2016 at 11:43:43 AM MDT
To: Charles Constant <charles@charlesism.com <mailto:charles@charlesism.com>>
Cc: Swift Evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>, Christopher Kornher <ckornher@me.com <mailto:ckornher@me.com>>
Reply-To: Charlie Monroe <charlie@charliemonroe.net <mailto:charlie@charliemonroe.net>>

I have mixed feelings about this since it may lead to redeclarations over and over of the same values instead of actually declaring an enum.

I have two suggested “improvements”

1) Make the enum String raw-representable. Name it somehow. This does not affect Erica’s original syntax.
2) Force an explicit name.

#2 does add to the length of function declarations, so it is a tradeoff. Perhaps the name could be optional, but...

#2 would improve debug representations of the value by providing a name that can be found in source code

In a full-featured metadata system, it would probably be nice to have a type for the enum to simply the handling of all enums.

#2 is more future-proof. Systems get more complex over time and one use of a type becomes many.
The enum type name (auto-generated or required, it makes no difference) would be scoped to the function’s namespace e.g. (fixing the typo) :

class MyImage {
  func scaleAndCropImage(
        image: UIImage,
    toSize size: CGSize,
    operation: ScaleCropFitFill{ .Fit | Fill} = .Fit

      ) -> UIImage {…}
}

would be equivalent to:

class MyImage {
   enum ScaleCropFitFill {
    case Fit
    case Fill
  }

  func scaleAndCropImage(
    image: UIImage,
    toSize size: CGSize,
    operation: ScaleCropFitFill = .Fit
  ) -> UIImage {…}
}

There are two ways that an implementation could evolve from having one use of the enum in a call to multiple uses;

1) The function is refactored into more functions internal to the original function’s namespace: module/class/struct/enum.
  In this case, it would be appropriate to leave the enum declaration in function declaration to indicate that this is the only public use of the enum.
2) More public functions are created that use the enum
  In this case, it would be appropriate to declare the enum within the same scope. Existing code would not be affected. Smart editors could provide this refactoring.

- Chris K

If we go back to your original example:

func scaleAndCropImage(
    image: UIImage,
    toSize size: CGSize,
    fitImage: Bool = true
    ) -> UIImage {

There is a different type of sugar that I would like to have: Having label stand for `true` when we have a defaulted boolean flag, whose default value is false.

At call site we either say:

scaleAndCropImage(image: myImage, toSize: mySize)

or:

scaleAndCropImage(image: myImage, toSize: mySize, fitImage)

We could still use:

scaleAndCropImage(image: myImage, toSize: mySize, fitImage: true)
or
scaleAndCropImage(image: myImage, toSize: mySize, fitImage: false)

Note that this is addressing a different situation: When we have multiple boolean flag parameters that can be combined like an OptionSet.

This is purely sugar: if the identifier matches the label of a defaulted to false boolean flag, it is interpreted as if the flag was passed as true. Other than that there is no effect.

I also like your idea as long as we put a limitation like what you proposed: Having it strictly be a UInt8 (or whatever) enum. Still the general resilience issues with enums remain and may get more complicated with this addition.

···

On May 31, 2016, at 3:00 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

On May 31, 2016, at 3:20 PM, Brent Royal-Gordon <brent@architechies.com> wrote:

func scaleAndCropImage(
  image: UIImage,
  toSize size: CGSize,
  operation: (.Fit | .Fill) = .Fit
  ) -> UIImage {

As I said the last time this proposal came up, I think this is great right up until the moment you need `operation` to be computed or kept in a variable. Then you need to start copying your anonymous enum type all over your source, and there's no central place to make changes. The same thing is true of tuples, but tuples are easy to structure and destructure from individual values on the spot; anonymous enums aren't really like that.

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.

-- E

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Correction/ Clarification. My assumption. The signature I am assuming is actually:

func scaleAndCropImage(
    image: UIImage,
    toSize size: CGSize,
    fitImage: Bool = false
    ) -> UIImage {

···

On May 31, 2016, at 3:27 PM, Hooman Mehr via swift-evolution <swift-evolution@swift.org> wrote:

If we go back to your original example:

func scaleAndCropImage(
    image: UIImage,
    toSize size: CGSize,
    fitImage: Bool = true
    ) -> UIImage {

There is a different type of sugar that I would like to have: Having label stand for `true` when we have a defaulted boolean flag, whose default value is false.

At call site we either say:

scaleAndCropImage(image: myImage, toSize: mySize)

or:

scaleAndCropImage(image: myImage, toSize: mySize, fitImage)

We could still use:

scaleAndCropImage(image: myImage, toSize: mySize, fitImage: true)
or
scaleAndCropImage(image: myImage, toSize: mySize, fitImage: false)

Note that this is addressing a different situation: When we have multiple boolean flag parameters that can be combined like an OptionSet.

This is purely sugar: if the identifier matches the label of a defaulted to false boolean flag, it is interpreted as if the flag was passed as true. Other than that there is no effect.

I also like your idea as long as we put a limitation like what you proposed: Having it strictly be a UInt8 (or whatever) enum. Still the general resilience issues with enums remain and may get more complicated with this addition.

On May 31, 2016, at 3:00 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On May 31, 2016, at 3:20 PM, Brent Royal-Gordon <brent@architechies.com <mailto:brent@architechies.com>> wrote:

func scaleAndCropImage(
  image: UIImage,
  toSize size: CGSize,
  operation: (.Fit | .Fill) = .Fit
  ) -> UIImage {

As I said the last time this proposal came up, I think this is great right up until the moment you need `operation` to be computed or kept in a variable. Then you need to start copying your anonymous enum type all over your source, and there's no central place to make changes. The same thing is true of tuples, but tuples are easy to structure and destructure from individual values on the spot; anonymous enums aren't really like that.

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.

-- E

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

> 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 May 31, 2016, at 3:46 PM, Vladimir.S <svabox@gmail.com> wrote:

On 31.05.2016 22:07, Matthew Johnson via swift-evolution wrote:

On May 31, 2016, at 2:04 PM, Erica Sadun <erica@ericasadun.com <mailto:erica@ericasadun.com> >>> <mailto:erica@ericasadun.com <mailto:erica@ericasadun.com>>> wrote:

On May 31, 2016, at 12:35 PM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com> >>>> <mailto:matthew@anandabits.com <mailto:matthew@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@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

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

What if (.Fit | .Fill) was just a shorthand for enums that you could use anywhere, like a tuple type?

let foo: (.Fit | .Fill) = .Fit
let bar: (.Fit | .Fill) = .Fill
let frob = cond ? foo : bar // foo and bar have the same type

You could typealias it too.

Félix

···

Le 1 juin 2016 à 20:05:06, Christopher Kornher via swift-evolution <swift-evolution@swift.org> a écrit :

On Jun 1, 2016, at 7:48 PM, Ricardo Parada via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On May 31, 2016, at 3:04 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

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.

This is my objection to this idea. It does not encourage reuse.

-1For me too. Introducing this quasi-enum would increase cognitive load with little, if any, net benefit. This is the sort of feature that looks great and works wonderfully in example apps, but does not scale well to real systems, where options show up in more methods through time, get passed around to helpers, stored, marshaled into various formats, etc.

As someone mentioned, this would probably be a good fit If Swift adopts a structural type system (I suppose, I have ever used a language with one to my knowledge, unless duck typing counts)

As syntactic sugar for a true enum declaration, it would be a “cool” feature, but reuse would still be problematic.

I would not be able to assign to a variable:

let selectedOperation = .fill

In order to then do this later in the program:

scaleAndCropImage(image: myImage, toSize: size, operation: selectedOperation)
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

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.

This is my objection to this idea. It does not encourage reuse.

-1For me too. Introducing this quasi-enum would increase cognitive load with little, if any, net benefit. This is the sort of feature that looks great and works wonderfully in example apps, but does not scale well to real systems, where options show up in more methods through time, get passed around to helpers, stored, marshaled into various formats, etc.

As someone mentioned, this would probably be a good fit If Swift adopts a structural type system (I suppose, I have ever used a language with one to my knowledge, unless duck typing counts)

As syntactic sugar for a true enum declaration, it would be a “cool” feature, but reuse would still be problematic.

···

On Jun 1, 2016, at 7:48 PM, Ricardo Parada via swift-evolution <swift-evolution@swift.org> wrote:
On May 31, 2016, at 3:04 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I would not be able to assign to a variable:

let selectedOperation = .fill

In order to then do this later in the program:

scaleAndCropImage(image: myImage, toSize: size, operation: selectedOperation)
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

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.

This is my objection to this idea. It does not encourage reuse.

-1For me too. Introducing this quasi-enum would increase cognitive load with little, if any, net benefit. This is the sort of feature that looks great and works wonderfully in example apps, but does not scale well to real systems, where options show up in more methods through time, get passed around to helpers, stored, marshaled into various formats, etc.

As someone mentioned, this would probably be a good fit If Swift adopts a structural type system (I suppose, I have ever used a language with one to my knowledge, unless duck typing counts)

As syntactic sugar for a true enum declaration, it would be a “cool” feature, but reuse would still be problematic.

there is no reuse problem in the interpretation I propose, and the long/short form names are completely interchangeable.

···

On Jun 2, 2016, at 5:05 AM, Christopher Kornher via swift-evolution <swift-evolution@swift.org> wrote:

On Jun 1, 2016, at 7:48 PM, Ricardo Parada via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
On May 31, 2016, at 3:04 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I would not be able to assign to a variable:

let selectedOperation = .fill

In order to then do this later in the program:

scaleAndCropImage(image: myImage, toSize: size, operation: selectedOperation)
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Yes, great point! I think this is a sign it’s better to just have one way with an enum, so there’s no deciding on which method to use, or reluctance to switch away from ad hoc enums because they felt nicer initially. And enums aren’t that much to write.

With the addition of a macro system in future Swift you could probably create your own ad hoc enums, and that would be perfect for something like a playground.

Patrick

···

On 2 Jun 2016, at 2:57 PM, Thorsten Seitz via swift-evolution <swift-evolution@swift.org> wrote:

Thinking of your example: where might the value for .fit or .fill come from? In most cases it won't be hardcoded in the call, but be either the result of a user setting or an algorithm. Both would need to be able to assign this value.

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@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Hi Laurent,

Do you have the details of your proposal, I missed it.

Thanks

···

On Jun 2, 2016, at 1:48 AM, L Mihalkovic <laurent.mihalkovic@gmail.com> wrote:

On Jun 2, 2016, at 5:05 AM, Christopher Kornher via swift-evolution <swift-evolution@swift.org> wrote:

On Jun 1, 2016, at 7:48 PM, Ricardo Parada via swift-evolution <swift-evolution@swift.org> wrote:

On May 31, 2016, at 3:04 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

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.

This is my objection to this idea. It does not encourage reuse.

-1For me too. Introducing this quasi-enum would increase cognitive load with little, if any, net benefit. This is the sort of feature that looks great and works wonderfully in example apps, but does not scale well to real systems, where options show up in more methods through time, get passed around to helpers, stored, marshaled into various formats, etc.

As someone mentioned, this would probably be a good fit If Swift adopts a structural type system (I suppose, I have ever used a language with one to my knowledge, unless duck typing counts)

As syntactic sugar for a true enum declaration, it would be a “cool” feature, but reuse would still be problematic.

there is no reuse problem in the interpretation I propose, and the long/short form names are completely interchangeable.

I would not be able to assign to a variable:

let selectedOperation = .fill

In order to then do this later in the program:

scaleAndCropImage(image: myImage, toSize: size, operation: selectedOperation)
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

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@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@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

- It breaks the ability to store a reference to the function in a variable

> of function type (ditto).

IMO the most important point. Probably we can have autogenerated names for such enums like:

function : func f(e: (.fit | .fill))->String
type is : (AdhocEnumFitFill)->String

or with no pre-defined syntax for such enum(so can't be used as type in code):
(AdhocEnumFitFill_2383748)->String
or just
(_enum_2383748)->String

But in this case two functions with different AdhocEnum_xxxx should be compatible between each other if cases exactly the same.
I.e. we should be able to write:

typealias MyFunc = func (x: (.fit | .fill))->String
// internally this will be (_enum_9823765)->String
let myfunc : MyFunc = f

Probably we could have such syntax for adhoc enums:
func f(e: enum(.fit, .fill)) {}

As for other questions, for myself, I use the analogue with tuples: if function requires a tuple, you can define tuple variable by typing its declaration manually. And you can have the same tuples in a number of functions, instead of structs. Yes, you will need to change tuple variables *anywhere* in your code if tuple in function declaration changed.
You have this freedom for tupes(ad-hoc structure). Why don't we need the same for enums ?

···

On 01.06.2016 7:24, Austin Zheng via swift-evolution 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@swift.org <mailto:swift-evolution@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@swift.org <mailto:swift-evolution@swift.org>
    https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution