> On Nov 15, 2016, at 09:24 , Dave Abrahams via swift-evolution 
> <[email protected]> wrote:
> 
> Speaking for myself: I think “probe-a-type” programming is in general a
> bad idea, and I'm opposed to adding features that encourage it.  It's
> almost always better to design entry points into supertypes (protocols,
> or base classes if you must ;->) with default implementations that can
> be overridden to do the work you need based on the characteristics of a
> subtype, rather than trying to make decisions in the caller based on the
> shape of the type.  When you *do* need probing, it's a good idea to make
> the set of possible subtypes a closed set, so the compiler can ensure
> you handle all cases—i.e., use an enum.

(I'm re-watching your WWDC 2105 talk about protocol-oriented programming, so I 
may end up with answers to the issues below.)

The thing that prompted my original post on this subject was an exploration of 
how to best implement a CAD program. In this case, something like Illustrator, 
where you can create, manipulate, and draw various shape types. I wanted to 
separate, as much as possible, the mathematical representation of the shape 
from the drawing and manipulating, and ideally have only one set of objects 
permanently instantiated (the mathematical representations of the shapes, i.e. 
the model).

So, I have a CanvasView that has a list of these shapes (a simple array). I 
have a set of tools (generally, a single instance of each, although when each 
gets instantiated can be changed in the design). The CanvasView triggers the 
drawing and the mouse handling for the set of shapes (CanvasObjects).

I've got something like this:

protocol Renderable { func renderer() -> Renderer? }
extension Renderable { func renderer() -> Renderer? { return nil } }

protocol Selectable { var selectionState: enum SelectionState }
protocol HitTestable { func hitTest(_ inPt: CGPoitn) }

protocol CanvasObject : HitTestable, Selectable {}
class Path : CanvasObject { }

protocol Renderer { func draw(in inCTX: CGContext) }
class PathRenderer : Renderer { }

You get the idea. Stop me if I'm way off base here.

I initially wanted Renderable.renderer() to be optional. I think I'm convinced 
returning an optional Renderer is equivalent.

Drawing
-------
CanvasView visits each CanvasObject in turn, instantiates an appropriate 
Renderer for the object (by calling Renderable.renderer()), calls 
Renderer.draw().

Mouse Handling
--------------
The currently-selected Tool is handed the mouse hit and the view. It iterates 
the objects, calling hitTest(). It then instantiates a handler based on the hit 
object type and current tool (might just be the current tool).

Problems
--------
The CanvasView has a list of CanvasObjects, forcing all objects to conform to 
all the protocols (e.g. Renderable, Selectable, HitTestable.) That is the 
CanvasView has a view onto the set of objects as complete objects, rather than 
a view of all Renderable objects, all HitTestable objects, etc. In this app, it 
may not be meaningful to talk about objects that are only renderable, but then 
again, it might (a grid could be renderable, but not selectable or hit 
testable; in practice it'll be implemented as a completely different entity, 
not part of the set of objects).

There is a problem of state management. Shapes are drawn differently depending 
on their state (e.g. normal, hovered, selected, sub-selected, being-snapped-to, 
etc.). I see no good way to store that state, except in the core object (e.g. 
Path). Alternatively, a parallel data structure that holds that state, but now 
I have to ensure instances of associated objects can be mapped back and forth. 
In fact, as I think about this more, I think it's a better solution, because 
it's conceivable there would be multiple views of the same model data, and the 
various states might be independent per view.

And performance will probably be okay, but needs to be considered.

I'm probably just making a mountain out of a molehill, but I want to make sure 
I'm understanding Swift thoroughly.


-- 
Rick Mann
[email protected]


_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to