[swift-evolution] Proposal: Stored properties for enums

Tommy van der Vorst tommy at pixelspark.nl
Thu Dec 10 08:50:28 CST 2015


Hi Jonathan,

I recently wrote a formula parser in Swift that also needs to keep the location+length for parsed expressions for syntax highlighting purposes. In my implementation I do not store the location+length in the expression tree itself, but maintain a separate map of [Expression: (location: Int, length: Int)] where Expression could be a Hashable enum type. 

I was more or less forced to do it this way because the expression logic is in a different framework that doesn't care about syntax highlighting, but I think it also nicely separates concerns between expression logic and view logic. Perhaps this solution also works for you.

Best,
Tommy.

> Op 10 dec. 2015, om 13:34 heeft Jonathan Hise Kaldma via swift-evolution <swift-evolution at swift.org> het volgende geschreven:
> 
> Not really. It certainly works, but it's hard to follow. Also, this example was imagining some type of editor with blocks on a timeline. So the pos and length should really be properties of the block, not of the data.
> 
> Without enum properties, I agree with Chris: enum inside struct is the best way to model this type of thing.
> 
> My problem isn't really that you can't do these things today, it's that the solutions are ugly, hard to read, and 10x as long as they need to be. Expressions for example can easily be modeled with structs conforming to a protocol:
> 
> protocol Expression {
> var loc, len : Int
> }
> 
> struct ValueExpression: Expression {
> var value: Double
> var loc, len : Int
> }
> 
> struct UnaryExpression: Expression {
> var op: Operator
> var expr: Expression
> var loc, len : Int
> }
> 
> struct BinaryExpression: Expression {
> var op: Operator
> var left, right : Expression
> var loc, len : Int
> }
> 
> But that's a lot of boilerplate to express something that's actually pretty simple conceptually. With enum properties it is just:
> 
> enum Expression {
> case Value(Double)
> indirect case Unary(Operator, Expression)
> indirect case Binary(Operator, Expression, Expression)
> var pos, len : Int
> }
> 
> Since readability is one of the main goals for Swift, I think it makes sense to include them.
> 
> Best,
> Jonathan
> 
>> 10 dec. 2015 kl. 12:00 skrev Al Skipp <al_skipp at fastmail.fm>:
>> 
>> Would the following construction address your use case?
>> 
>> struct DataInfo<DataType> {
>> var data: DataType
>> var pos, length: Float
>> }
>> 
>> enum Block {
>> case Audio(DataInfo<AudioData>)
>> case Video(DataInfo<VideoData>)
>> }
>> 
>> 
>>> On 10 Dec 2015, at 10:14, Jonathan Hise Kaldma via swift-evolution <swift-evolution at swift.org> wrote:
>>> 
>>> 
>>>>> 10 dec. 2015 kl. 02:01 skrev Chris Lattner <clattner at apple.com>:
>>>>> 
>>>>> On Dec 9, 2015, at 12:28 PM, Jonathan Hise Kaldma via swift-evolution <swift-evolution at swift.org> wrote:
>>>>> But it breaks down if you need to keep track of more data for each tree node, e.g. if you’re making a parser and need to keep track of source location. This could easily be solved with stored properties:
>>>>> 
>>>>> enum Expression {
>>>>> case Number(Double)
>>>>> case Variable(String)
>>>>> indirect case Unary(Operator, Expression)
>>>>> indirect case Binary(Operator, Expression, Expression)
>>>>> 
>>>>> var location: Int = 0
>>>>> var length: Int = 0
>>>>> }
>>>> 
>>>> The concern with doing this is that Swift currently distinguishes clearly between product & sum types, and this is a good thing.  With your proposal, there would be no difference between:
>>>> 
>>>> struct X {
>>>> var a, b : Int
>>>> }
>>>> 
>>>> and:
>>>> 
>>>> enum X {
>>>> var a, b : Int
>>>> }
>>> 
>>> The difference would be that you can't initialize the enum, since it doesn't have any cases. Essentially a struct would be an enum with zero cases.
>>> 
>>>> As such, there would be no reason to have concepts in the language.  Some might argue that this is good (fewer things == better), but I’d argue that this is worse, because it can be better for clearly different things to be... different.
>>> 
>>> Struct would be the zero-case subset of enum. Related, but different.
>>> 
>>>> Further, Swift has a simple way to express this today use: an enum inside of a struct.  As far as I can tell, the only bad thing about this is that it breaks pattern matching over the recursive case.  However, this is a already an annoying aspect of swift’s current design that show up in other ways: for example, structs are generally more powerful than tuples, except that tuples can be pattern matched over.
>>> 
>>> The problem with an enum inside a struct, is that, as Dave pointed out, it puts more focus on the things that are similar, and less on the things that are different, which is often the opposite of what you want.
>>> 
>>> Also, it usually doesn't really capture what you're trying to model.
>>> 
>>> struct Block {
>>> var type: BlockType
>>> var pos, length : Float
>>> }
>>> 
>>> enum BlockType {
>>> case Audio(AudioData)
>>> case Video(VideoData)
>>> }
>>> 
>>> Why is BlockType a different thing? A block can be audio or video, not something else. And modeling different cases of something, isn't that what enums are for? It would be much more elegant and readable to just say:
>>> 
>>> enum Block {
>>> case Audio(AudioData)
>>> case Video(VideoData)
>>> var pos, length : Float
>>> }
>>> 
>>>> IMO, the right way to fix this is to introduce the concept of pattern matching over structs and classes.  If you dig through history, you’ll see that Joe Groff implemented a sketch of this functionality in the compiler, but it was never fully baked so it was turned off before Swift 1.0, and eventually got removed.  A better baked out design and implementation could fix the problems you raise without causing a conflation between structs and enums.
>>>> 
>>>> - Chris
>>> 
>>> Thanks! I'll take a look.
>>> 
>>> And thanks for a great language!
>>> 
>>> Best,
>>> Jonathan
>>> _______________________________________________
>>> 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



More information about the swift-evolution mailing list