[swift-users] It seems like we really need an #include preprocessor directive?

davelist at mac.com davelist at mac.com
Sat Mar 11 17:30:26 CST 2017


> On Mar 11, 2017, at 3:12 PM, Edward Connell via swift-users <swift-users at swift.org> wrote:
> 
> Observations about difining an object
> 	• Structs can't inherit and classes shouldn't inherit, final concrete types should be flat
> 	• Protocols need to be adopted by the final concrete type, otherwise constraint specializations aren't correctly applied
> This creates a really ugly code duplication situation when you have multiple object variants that adopt the same protocols.
> 
> The storage declaration, common initialization, common didSet, etc... for protocol member variables must be duplicated for every instance. 
> If I have 20 objects that have the same base set of 15 vars, this turns into a maintenance/bug nightmare.
> 
> I noticed the use of GYB in the swift source code. 
> I don't want to involve python in anything I do, and I don't want to mess up my code/build with all that stuff.
> 
> It seems that an easy workaround would be an #include statement. 
> The boiler plate can be put in a separate file and included wherever it's needed. 
> One piece of code, one tool, one set of bugs.
> 
> Has this been considered? Or is there a better way to handle this problem.
> 
> Thanks, Ed


Without seeing the exact problem you're working on, I can't say for certain, but this does seem like a very reasonable case for using inheritance. So I disagree with your statement that "classes shouldn't inherit". Yes, if your writing a framework, you might decide that some classes should not be subclassed publicly (that was the entire argument about making final be the default in Swift), but there's nothing wrong with still using inheritance for those classes in your framework with only the deepest subclass being public and then also marked final so it can't be subclassed.

I suppose you could argue that you want a value type (instead of a reference type) so you want to use a struct and can't accomplish this with a struct other than by repeating the same 15 vars and there's no way to "automate" that. If that's the case, I guess I would argue the way to do it (which would require an enhancement to Swift) would be to allow protocols (or a variation on protocols) to define instance variables (vs. just requiring that the exist right now by saying it must have a getter and possibly setter). I'm by no means a language design expert so I don't know what other problems this might cause but I don't think you're going to see any kind of #include statement in Swift.

Another option I might see some use for "partial inheritance" with structs where the compiler would always know the exact type and determine which methods would be called  (i.e., no runtime vtable or objc_msgsend - it would all be done statically by the compiler but you could declare one struct by building upon another struct. 

For example

struct Foo {
  var x = 0
}

struct Bar: Foo { // so Bar also has an x instance variable
   var y = 0
}

var b = Bar()
b.x = 3
b.y = 4

// but you couldn't do
var f: Foo = b // since Foo doesn't have a y

Again, I haven't fully thought through the implications and don't have enough language design experience to know what other problems this might cause. And I don't know if this is worth the increased cognitive load of having to check multiple structs like you do with class inheritance to see what methods/variables are defined in base classes.

But all I can say, is I don't see a good solution for your problem (other than using inheritance) in the current version of Swift. I probably would declare a protocol for those 15 variables and have each struct conform to that protocol so you make certain you don't forget one of them in one of the structs but that doesn't write the declarations for you.

Dave Reed







More information about the swift-users mailing list