[modelio] Update for iOS 10.3 beta 1 - #1601
Conversation
spouliot
left a comment
There was a problem hiding this comment.
I'm not sure we want to expose Protocol in the API
| public void IndexerTest () | ||
| { | ||
| using (var obj = new MDLObject ()) { | ||
| var key = new Protocol ("MDLComponent"); |
There was a problem hiding this comment.
I'm not sure we want to expose Protocol like this in the API. At best it's not very type safe, I'd better use
var key = new Protocol (typeof (MDLComponent));
My first thought was to abuse [BindAs] but a conversion from Protocol to System.Type, with additional checks to ensure it's a protocol, can be costly if done repetitively...
Maybe we can just provide a [Wrapper] that calls a conversion method ? and also expose that as a new Protocol.ctor(System.Type) ?
@rolfbjarne @dalexsoto thoughts ?
There was a problem hiding this comment.
I think just a [Wrapper] that calls a conversion method (or a new Protocol ctor) would be fine.
BTW your example is wrong 😄 It should be:
var key = new Protocol (typeof (IMDLComponent));
There was a problem hiding this comment.
Yep, agree on just the Wrapper 👍
| return ObjectForKeyedSubscript (key); | ||
| } | ||
| set { | ||
| SetObject (value, key); |
There was a problem hiding this comment.
that's confusing because your new SetObject (even if internal) is not symmetric with the existing GetObject
| [iOS (10,3), TV (10,2), Mac (10,12,4)] | ||
| [Export ("componentConformingToProtocol:")] | ||
| [return: NullAllowed] | ||
| IMDLComponent IsComponentConforming (Protocol protocol); |
There was a problem hiding this comment.
Is makes it sound boolean, but this is not what it returns. Seems to me that Get is the action (not question) being done.
Also it seems to be related with the previous method, so GetComponent would match.
There was a problem hiding this comment.
@spouliot I totally agree with you but I wanted to keep it close to MDLObject's IsComponentConforming...
Most of the changes in this PR are about aligning MDLObject and MDLAsset.
There was a problem hiding this comment.
Let's fix the bad one with an [Obsolete] and add a new, accurate, name :)
There was a problem hiding this comment.
Maybe GetConformingComponent? That's a bit more descriptive and closer to what ObjC calls it (which makes finding it easier).
There was a problem hiding this comment.
Ah, I see the SetComponent method now, GetComponent would be the opposite method (I assume at least, since Apple named them quite differently).
There was a problem hiding this comment.
Yea so in the headers setComponent:forProtocol: and componentConformingToProtocol: have the exact same description:
Extensible component support that allows user of ModelIO to customize MDLAssets to fit their format and workflow.
So I'm going for GetComponent instead of IsComponentConforming.
| } | ||
|
|
||
| [iOS (10,3), TV (10,2), Mac (10,12,4)] | ||
| public IMDLComponent this [Protocol key] { |
There was a problem hiding this comment.
there's already a this that returns something else... check FxDG but I don't think we should expose it this way. That can get confusing source wise when the argument type is not clear.
There was a problem hiding this comment.
FxDG (Framework Design Guideline)?
There was a problem hiding this comment.
Mmh here's the guideline: https://msdn.microsoft.com/en-us/library/ms229006(v=vs.110).aspx
AVOID indexers with parameter types other than System.Int32, System.Int64, System.String, System.Object, or an enum.
So Protocol is definitely not recommended.
DO NOT provide more than one family of overloaded indexers in one type.
I guess that validates your point @spouliot. As I understand it it's fine to "overload" an indexer (as in have an indexer that's using an other indexer in the same type) but it's wrong to create a 2nd and different family of indexers.
| namespace XamCore.ModelIO { | ||
| public partial class MDLObject { | ||
| [iOS (10,3), TV (10,2), Mac (10,12,4)] | ||
| public IMDLComponent this [Protocol key] { |
There was a problem hiding this comment.
should match how MDLAsset turns out...
|
|
||
| [Internal] | ||
| [Export ("setObject:forKeyedSubscript:")] | ||
| void SetObject ([NullAllowed] IMDLComponent obj, Protocol key); |
There was a problem hiding this comment.
are those just doing the same as the setComponent:forProtocol: and componentConformingToProtocol: above ? in that case maybe we should not expose them ?
There was a problem hiding this comment.
Yes so objectForKeyedSubscript:'s description is:
Allows shorthand [key] syntax for
componentConformingToProtocol:
@spouliot correct me if I'm wrong but this is basically the indexer I implemented initially (public IMDLComponent this [Protocol key] which was sentenced to die because there's already one).
|
|
||
| [Internal] | ||
| [Export ("setObject:forKeyedSubscript:")] | ||
| void SetObject ([NullAllowed] IMDLComponent obj, Protocol key); |
There was a problem hiding this comment.
same (not sure we need those, tests would confirm)
|
|
||
| [Export ("componentConformingToProtocol:")] | ||
| [return: NullAllowed] | ||
| IMDLComponent IsComponentConforming (Protocol protocol); |
There was a problem hiding this comment.
that's old, but badly named :(
There was a problem hiding this comment.
Ah well you found the origin of my IsComponentConforming...
| void RemoveObject (MDLObject @object); | ||
|
|
||
| [iOS (10,3), TV (10,2), Mac (10,12,4)] | ||
| [Abstract] |
There was a problem hiding this comment.
breaking change, you cannot add abstract methods as existing subclasses won't have them
There was a problem hiding this comment.
Ah damn, good point I missed that.
| MDLObject GetObjectAtIndexedSubscript (nuint index); | ||
|
|
||
| [iOS (10,3), TV (10,2), Mac (10,12,4)] | ||
| [Abstract] |
|
Build failure |
|
Introspection-mac |
|
Unrelated tests failures (due to the move to Xcode8.3): |
| [iOS (10,3), TV (10,2), Mac (10,12,4)] | ||
| [Abstract] | ||
| [Export ("objectAtIndexedSubscript:")] | ||
| MDLObject GetObjectAtIndexedSubscript (nuint index); |
There was a problem hiding this comment.
Just GetObject would be better.
| [Test] | ||
| public void IndexerTest () | ||
| { | ||
| using (var obj = new MDLAsset ()) { |
There was a problem hiding this comment.
I think you need a version check here, for Xcode 8.3.
| public void IndexerTest () | ||
| { | ||
| using (var obj = new MDLObject ()) { | ||
| var key = new Protocol ("MDLComponent"); |
There was a problem hiding this comment.
I think just a [Wrapper] that calls a conversion method (or a new Protocol ctor) would be fine.
BTW your example is wrong 😄 It should be:
var key = new Protocol (typeof (IMDLComponent));
847fe43 to
a5c2034
Compare
|
Alright so:
For The first one being:
The second being:
|
|
Build failure |
rolfbjarne
left a comment
There was a problem hiding this comment.
Also please add tests for the new Protocol constructor.
|
|
||
| public Protocol (Type type) | ||
| { | ||
| this.handle = Class.GetHandle (type); |
There was a problem hiding this comment.
This is not correct.
-
First check that the type is an interface, otherwise it can't be a protocol:
if (!type.IsInterface) throw new ArgumentException (string.Format ("'{0}' is not a protocol.", type.FullName)); -
Then get the Protocol attribute, and get the name of the protocol from there:
var protocols = type.GetCustomAttributes (typeof (ProtocolAttribute), false); if (protocols.Count == 0) throw ... var protocol = protocols [0]; var protocolName = protocol.Name; handle = objc_getProtocol (protocolName); if (handle == IntPtr.Zero) throw ...
There was a problem hiding this comment.
Mmh didn't realized I could dive into the managed type like that! Much better thanks.
|
Build failure |
|
|
||
| public Protocol (Type type) | ||
| { | ||
| var exception = new ArgumentException (string.Format ("'{0}' is an unknown protocol", type.FullName)); |
There was a problem hiding this comment.
This creates an exception instance for every protocol created (thru this .ctor). This is not efficient, use something like:
if (type.IsInterface) {
foreach (var pa in type.GetCustomAttributes<ProtocolAttribute> (false)) {
handle = objc_getProtocol (pa.Name);
if (handle != IntPtr.Zero)
return;
}
}
if (handle == IntPtr.Zero)
new ArgumentException (string.Format ("'{0}' is an unknown protocol", type.FullName));
There was a problem hiding this comment.
Also having different exception messages for each condition gives you valuable information (which check failed?).
| [Export ("components", ArgumentSemantic.Copy)] | ||
| IMDLComponent[] Components { get; } | ||
|
|
||
| [Internal] |
There was a problem hiding this comment.
maybe [Advanced] but not [Internal]. The main reason is that Type is easier (and type safe) to use, but it would be costly in a loop, e.g.
foreach (var component in list)
x.SetComponent (type);
vs
var p = new Protocol (type);
foreach (var component in list)
x.SetComponent (p);
It also makes it possible to override the method in a subclass.
| [Wrap ("SetComponent (component, new Protocol (type))")] | ||
| void SetComponent (IMDLComponent component, Type type); | ||
|
|
||
| [Internal] |
| #if XAMCORE_4_0 | ||
| [Internal] | ||
| #endif | ||
| [Obsolete ("Use SetComponent (Type protocol)")] |
There was a problem hiding this comment.
remove both [Obsolete] and [Internal]
| #if XAMCORE_4_0 | ||
| [Internal] | ||
| #endif | ||
| [Obsolete ("Use GetComponent (Type protocol)")] |
There was a problem hiding this comment.
Obsolete IsComponentConforming but expose GetComponent (Protocol protocol) for the same reasons as above
| throw new ArgumentException (String.Format ("'{0}' is an unknown protocol", name)); | ||
| } | ||
|
|
||
| public Protocol (Type type) |
|
Build failure |
0238842 to
640892f
Compare
|
Build failure |
|
Unrelated test failures
@rolfbjarne add one simple test in Also fixed the |
MDLAssetTest(copy fromMDLObjectTest).