Re: Swift generics, circular type declarations, and segfaults, oh my!
Re: Swift generics, circular type declarations, and segfaults, oh my!
- Subject: Re: Swift generics, circular type declarations, and segfaults, oh my!
- From: has <email@hidden>
- Date: Sat, 05 Sep 2015 00:31:15 +0100
On 03/09/2015 19:57, Quincey Morris wrote:
On Sep 3, 2015, at 11:16 , has <email@hidden
<mailto:email@hidden>> wrote:
* Using an instance as a factory for its own class is contrary to
general usage, so is a smell at best. It’s a job for a class func.
No, it's fine. It's for an Apple event query builder. Any odd smells
are probably the Apple event architecture's doing.
Huh? Why is it fine to create an additional unnecessary object? And
what has this got to do with Apple events?
At risk of derail...
Apple event queries (object specifiers) are constructed as linked lists.
I'm just putting a high-level user-friendly wrapper around that. Either
the wrapper vends a new object each time the list is appended to, or it
creates a single wrapper object that appends the list internally. The
first approach is simpler and safer to use since there's no mutable
state, and the cost of instantiating a few additional objects is trivial
compared to the time it takes to send an AE and receive a reply, so I'm
not worried about that. It's a tested, proven design - if you really
want to understand it in detail then I suggest installing the original
Python version (http://appscript.sourceforge.net/) and working through
the tutorial.
My concern here is how to implement a Swift version, which means
leveraging the Swift type system as much as practical and fighting it as
little as I can. The Swift prototype
(https://bitbucket.org/hhas/appleeventbridge/) currently uses a very
simple class hierarchy consisting of a per-application code-generated
Specifier class that inherits from a standard library-supplied base class:
AbstractBase // defines standard functionality
Specifier // adds app-specific properties, elements, commands,
and standard selectors
Since there's only one concrete Specifier class, methods (and vars) that
return new Specifier instances, standard methods inherited from
AbstractBase can just declare their return type as 'Self', and the
compiler will figure out the correct return type automatically.
The downside of the above approach is that not all specifier types
(insertion, object, elements, etc.) support the same features, so some
of the exposed's methods won't always work. It'd be better to represent
each type of specifier as a different subclass that exposes only those
methods that are valid on it, making invalid calls impossible:
AbstractBase // defines standard functionality
AbstractSpecifier // adds app-specific commands
InsertionSpecifier
ObjectSpecifier // adds app-specific properties and elements
ElementsSpecifier // adds standard selectors
The catch is that I can no longer declare all methods' return types as
'Self', because they now return several (albeit related) types.
ObjectSpecifiers need to vend InsertionSpecifiers, ObjectSpecifiers and
ElementsSpecifiers. ElementsSpecifiers need to vend ObjectSpecifiers and
ElementsSpecifiers. And each scriptable application needs its own
code-generated versions of these classes too. The code generator can
insert the correct type for app-defined vars, but the standard inherited
methods can only (afaik) specify the correct return type if they're
defined as a generic class, allowing the exact types to be supplied as
parameters:
class AbstractBase<InsertionType,ObjectType,ElementsType> {
}
thus allowing each application glue to parameterize that class with its
own exact types, e.g.:
AbstractBase<FinderInsertion,FinderObject,FinderElements>
Which takes us back to the problem described in my previous email, where
the Swift compiler and runtime don't seem to like this circular
referencing of related type names very much. Worst comes to the worst,
I'll just have to throw _everything_ into the code generator, but that
offends even my slobbish nature, so if there's a way to keep the
standard functionality in a generic base class without Swift puking on it.
Chained var/method calls let you build and send AE queries using a
non-atrocious syntax, e.g.:
let result: [String] = try TextEdit().documents[1].text.words.get()
Again: huh? Where’s the factory method in this?
You're looking at them (this is why I prefer not to use GoF jargon
myself). The `documents` var returns a new elements specifier, `[1]`
returns a new object specifier, `text` returns a new object specifier,
`words` returns a new elements specifier. Very easy to use, just a pain
to explain how to implement. :p
Thanks,
has
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden
References: | |
| >Swift generics, circular type declarations, and segfaults, oh my! (From: has <email@hidden>) |
| >Re: Swift generics, circular type declarations, and segfaults, oh my! (From: Fritz Anderson <email@hidden>) |
| >Re: Swift generics, circular type declarations, and segfaults, oh my! (From: has <email@hidden>) |
| >Re: Swift generics, circular type declarations, and segfaults, oh my! (From: Quincey Morris <email@hidden>) |