On 03/09/2015 19:57, Quincey Morris wrote:
On Sep 3, 2015, at 11:16 , has <hengist.p...@virgin.net <mailto:hengist.p...@virgin.net>> 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 (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to