Re: Cocoa et al as HCI usability problem
Re: Cocoa et al as HCI usability problem
- Subject: Re: Cocoa et al as HCI usability problem
- From: Peter Duniho <email@hidden>
- Date: Mon, 19 May 2008 14:49:01 -0700
On May 19, 2008, at 2:05 PM, Greg Titus wrote:
On May 19, 2008, at 12:08 PM, Peter Duniho wrote:
[...]
However, _with_ reflection we can do much of the same kinds of
things that Obj-C does, without knowing in advance the classes
that might use the NSUndoManager class.
One advantage I see in Cocoa is that, because classes may respond
to selectors that they didn't even declare, NSUndoManager can
simply set a temporary variable, and then catch a selector to be
saved away for later invocation. This makes the reflection aspect
("introspection" in Objective-C) more transparent.
Right. I'm glad you see that. Another place to look for the same
type of thing is Distributed Objects in Obj-C. It's another piece
of the frameworks that use the ability to catch invocations "in
flight". In that case, in order to serialize the method and
arguments, send the data across the network or between threads,
unserialize on the other side, and invoke in that other machine/
process/thread.
Well, except that this would generally be implemented by the
framework, no?
In .NET, it supports remote invocations, and this uses (in part)
reflection, but the application writer never needs to know the gory
details. I agree that reflection is slightly more awkward than
what's been presented in terms of Objective-C's message paradigm, and
I accept that as a benefit for the authors of the framework. But the
end-user doesn't need any of this, or even need to care how it's
implemented. Imposing a particular language on the end-user in order
to support the framework author doesn't seem compelling to me.
Thanks very much for the example. The same sort of facility
(getting method from name) is available in Objective-C, of course,
and Andreas Mayer replied on the list an interesting example of how
he uses that in AppleScript handling. What C# seems to be missing
is the reverse facility (going from a compiled method call back out
to name + arguments), which my sample NSUndoManager code demonstrated.
Well, I didn't show the invocation code because it's trivial. You
just use the MethodInfo object along with the target instance and the
saved parameters to call the MethodInfo.Invoke() method.
Interestingly, given your earlier remarks about the desirability of
compile time checking, in Objective-C [[undoManager
prepareWithInvocationTarget:self] setColor:mColor] is type checked.
The compiler knows about the -setColor: method declaration it has
seen and can check that mColor is an appropriate type.
With reflection, you can have type checking, though it's more
explicit. With the anonymous method (as I said, more idiomatic in C#
anyway), type checking is implicit.
(Because Obj-C still lets you call any method on any object the
result of bad typing here will be a warning rather than an error,
but Obj-C programmers generally learn to pay attention to and fix
all warnings.) Whereas I suspect that when you are using the
reflection facilities in C# in the way you are above, that there is
no type checking being performed. Is that correct?
There's no compile-time type checking with reflection, that's correct
(though you can certainly include run-time type checking if you want
to ensure your program doesn't blow up :) ). That's certainly one
reason to avoid reflection if it's not necessary (and it wouldn't be
in this particular example...I offered the reflection example as a
way of illustrating the more general point).
The fact is, often there are better alternatives to reflection in
C#. I simply presented reflection as a "closest match" to the
specific Objective-C functionality being shown.
That is one of the advantages of having the dynamism built into the
language runtime rather than a reflection API built on top. Another
advantage is that code can be written that doesn't need to know
whether reflection is being used or not. In the Distributed Objects
case, for instance, it is very common to pass around proxies as
arguments to code that doesn't have any idea that the methods it is
calling on those argument objects actually get forwarded somewhere
else entirely.
I haven't had time to look at the Distributed Objects example.
However, I suspect that there are equivalent idioms in C#/.NET that
don't require the end-user (that is, the application writer) to know
about reflection. The reflection aspect would be "under the hood".
In reality, I would (and have) more likely implement an undo
manager that uses anonymous methods. Then all you're saving to
your undo state is a delegate that does what you want (assumes the
"property" semantic I posted):
undoManager.AddUndo(delegate { color = mColor; });
This is more idiomatic in C# and wouldn't need all that messy
reflection stuff. Executing the undo is a simple matter of
invoking the delegate that was passed, a simple one-line operation
that reads like a method call (note that the use of the name
"delegate" is very different in C# than in Cocoa...C# "delegate"
is more like a function pointer than an actual object to which
some selector has been delegated).
Like I said earlier, I don't know C#, but this doesn't appear to me
what the code would actually look like. The trouble is that the
whole point is we want to be able to undo a previous -setColor:
call. If mColor is a reference to the "this" object's current
color, then at the time that the undo happens, the value of the
reference "mColor" will be the _new_ color, not the old color that
we want to restore.
Sorry, you're right. Typo on my part. The actual code would look
like this:
NSColor colorPrev = color;
undoManager.AddUndo(delegate { color = colorPrev; });
The local variable "colorPrev" would be "captured" and stored as part
of the anonymous method. For a given instance of the anonymous
method, it will have the value exactly as it was at the moment that
the anonymous method was created (i.e. at the time that AddUndo() was
called).
So that line of code will just set it to itself. What is needed is
to store the mColor value as it is at the time the anonymous
delegate is created, not at the time the delegate is executed. Is
it possible for an anonymous method to have its own instance
variables (in this case, to store the old color)?
Captured variables are essentially instance variables for the
anonymous method.
From looking at the docs it doesn't appear to. Nor does it seem
possible to do so with named method delegates.
I don't understand the comments saying that you can't do something
similar in Java. Java has the same kind of reflection features
that C# has. The anonymous method approach wouldn't work, as Java
doesn't have anything equivalent to C# delegates, but Java does
have interfaces and using those with anonymous types in lieu of
anonymous methods is a common Java idiom that works well.
Only with fixed signatures, though.
Not really. Using an anonymous type in Java in lieu of an anonymous
method in C#, you can use local variables (declared "final") in a
similar fashion as that used to capture variables in C#. So you'd
just need a single interface, and then reference the necessary local
variable data from within an anonymous type implementing that interface.
I've yet to run into anything in Java where I could have used an
anonymous method in C#, but couldn't get an anonymous type to work in
a similar fashion in Java. I find the anonymous method syntax more
elegant, but the Java approach is workable and generally feature-
identical.
Pete
_______________________________________________
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