Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DYN-2588] Enable ArbitraryDimensionArrayImport attribute to function return values, apply this to Dictionary.Values getter #13055

Merged
merged 7 commits into from
Jun 27, 2022

Conversation

aparajit-pratap
Copy link
Contributor

@aparajit-pratap aparajit-pratap commented Jun 21, 2022

Purpose

Fixes a case like this that would fail. It now works as expected.
image

This introduces an API break but I think it's a necessary fix. Alternatively, we can add a new property with a different but similar name to Values and deprecate Values.

Declarations

  • The codebase is in a better state after this PR
  • Is documented according to the standards
  • The level of testing this PR includes is appropriate
  • User facing strings, if any, are extracted into *.resx files
  • All tests pass using the self-service CI.
  • Snapshot of UI changes, if any.
  • Changes to the API follow Semantic Versioning and are documented in the API Changes document.
  • This PR modifies some build requirements and the readme is updated

Release Notes

(FILL ME IN) Brief description of the fix / enhancement. Mandatory section

Reviewers

@saintentropy

FYIs

@Amoursol what do you think?

@Amoursol
Copy link
Contributor

@aparajit-pratap the API break would only be negative if a user was relying on the failure in this case, correct? If so, that should be little to no exposure, and the benefit should outweigh it.

@aparajit-pratap
Copy link
Contributor Author

aparajit-pratap commented Jun 22, 2022

@aparajit-pratap the API break would only be negative if a user was relying on the failure in this case, correct? If so, that should be little to no exposure, and the benefit should outweigh it.

@Amoursol sorry, I wasn't clear with my question. I think there might be other consequences of the API break such as user code relying on this property and finding it to be broken as well. However, what I wanted from you was, if you were okay with the idea of introducing a new node with a different name than Values that we could expose while deprecating Values if we decided we should avoid the API break at all costs.

@Amoursol
Copy link
Contributor

@aparajit-pratap the API break would only be negative if a user was relying on the failure in this case, correct? If so, that should be little to no exposure, and the benefit should outweigh it.

@Amoursol sorry, I wasn't clear with my question. I think there might be other consequences of the API break such as user code relying on this property and finding it to be broken as well. However, what I wanted from you was, if you were okay with the idea of introducing a new node with a different name than Values that we could expose while deprecating Values if we decided we should avoid the API break at all costs.

@aparajit-pratap preference would be to keep "Values" as it correlates with the output port names from the other nodes and may cause confusion in the userbase, but yes, if we deem is necessary to deprecate we can find an alternative name.

@aparajit-pratap aparajit-pratap requested a review from sm6srw June 22, 2022 19:31
Copy link
Contributor

@sm6srw sm6srw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@aparajit-pratap
Copy link
Contributor Author

LGTM!

@sm6srw any idea how severe is the API break if a new attribute is added to an API, in this case, the public property? Will user code need to be rebuilt?

@sm6srw
Copy link
Contributor

sm6srw commented Jun 23, 2022

Looks like it is API breaking according to https://stackoverflow.com/questions/1456785/a-definitive-guide-to-api-breaking-changes-in-net. I assume a recompile is needed? This is not something I have run into.

}

return false;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unused

@aparajit-pratap aparajit-pratap requested a review from sm6srw June 24, 2022 23:18
@aparajit-pratap aparajit-pratap changed the title Re-add allowrankreduction attribute to Dictionary.Values Enable ArbitraryDimensionArrayImport attribute to function on return values, apply this to Dictionary.Values getter Jun 24, 2022
@aparajit-pratap
Copy link
Contributor Author

aparajit-pratap commented Jun 24, 2022

@Amoursol @sm6srw I have avoided the behaviour change by removing the AllowRankReduction attribute. Instead, I applied the ArbitraryDimensionArrayImport attribute to the return value of Dictionary.Values that fixes the issue as well as does not change the original behaviour, aka, a list of a single value is still returned as a list of a single value.

@aparajit-pratap aparajit-pratap changed the title Enable ArbitraryDimensionArrayImport attribute to function on return values, apply this to Dictionary.Values getter [DYN-2588] Enable ArbitraryDimensionArrayImport attribute to return values, apply this to Dictionary.Values getter Jun 25, 2022
@aparajit-pratap aparajit-pratap changed the title [DYN-2588] Enable ArbitraryDimensionArrayImport attribute to return values, apply this to Dictionary.Values getter [DYN-2588] Enable ArbitraryDimensionArrayImport attribute to function return values, apply this to Dictionary.Values getter Jun 25, 2022
@Amoursol
Copy link
Contributor

@Amoursol @sm6srw I have avoided the behaviour change by removing the AllowRankReduction attribute. Instead, I applied the ArbitraryDimensionArrayImport attribute to the return value of Dictionary.Values that fixes the issue as well as does not change the original behaviour, aka, a list of a single value is still returned as a list of a single value.

Brilliant, thanks @aparajit-pratap! This should safely allow us to make this change.

Copy link
Contributor

@sm6srw sm6srw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still try to understand exactly how this work but LGTM!

src/Engine/ProtoCore/FFI/CLRDLLModule.cs Show resolved Hide resolved
public IEnumerable<object> Values => D.Values;
public IEnumerable<object> Values
{
[return: ArbitraryDimensionArrayImport]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have not seen this before. Can you give me some hints about how this is different for the previous solution?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ArbitraryDimensionArrayImport and AllowRankReduction attributes are slightly different in behaviour. The first one can be used for function parameters and return values and allows arbitrary ranked arrays and mixed rank arrays from being passed and returned to and from functions. The latter attribute can only be applied to return value of a function. It returns a single value in the case that a function returning a list returns a list of a single value (reduces the rank of a return value).

The thing that both attributes are similar in is that both of them convert the value to arbitrary rank, if it is an array (and if it's an array containing more than one value in the case of AllowRankReduction).

In this case, we don't want to change the behaviour of Dictionary.Values as far as possible, so we don't want to use AllowRankReduction but use ArbitraryArrayDimensionImport attribute instead so we can support returning arbitrarily ranked arrays.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ArbitraryArrayDimensionImport in the past even though it could be applied to function return values and function parameters, we didn't add support to make it handle return values. So, in this PR, I've added that support as well as applied it to Dictionary.Values.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good. And this approach will not break the API?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No idea but from my testing, it doesn't appear to break the API. I tested it with another assembly that referenced Dictionary.Values and I didn't need to rebuild it. However, @mjkkirschner would know better as he's better with this kind of stuff.

Copy link
Member

@mjkkirschner mjkkirschner Jun 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is fine, can you name the syntax though? so I can research further- my googling is coming up short - [return: ArbitraryDimensionArrayImport]

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, I see, it's an attribute only of the return value, not the method.

@aparajit-pratap aparajit-pratap requested a review from sm6srw June 27, 2022 15:15
var returnTypeAtts = minfo.ReturnTypeCustomAttributes;
if (returnTypeAtts != null)
{
attributes.AddRange(returnTypeAtts.GetCustomAttributes(false).Cast<Attribute>());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so this seems to be compressing a bit of information - we seem to take the return type attribute and then assign it to a list of attributes for the entire node (method) - whats the purpose of making it an attribute of the return value if we just add it to the same list of attributes on the FFIMethodAttributes ?

Copy link
Contributor Author

@aparajit-pratap aparajit-pratap Jun 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we could make it an attribute on the entire method as we do for AllowRankReduction. Currently, the ArbitraryDimensionArrayImport attribute's usage is for parameters and return values, and if we were to change, it, it would need to be applied to methods and properties as we do for AllowRankReduction. Not sure if that is a bigger change and/or API break. I believe with the return qualifier it also makes it clearer that it's applied to the return value and not to something else on the method.

@mjkkirschner
Copy link
Member

@aparajit-pratap it looks good to me, I'm a bit confused by the purpose of using the return qualifier when assigning the attribute since it appears we just lump it together with other attributes, but I don't think it hurts anything unless we might want to support that same attribute on the whole method in some cases where it does something else?

@mjkkirschner
Copy link
Member

@aparajit-pratap I've started: https://master-5.jenkins.autodesk.com/job/Dynamo/job/DynamoSelfServe/job/pullRequestValidation/6392/ as the last test run on this branch had 3 failures.

@aparajit-pratap aparajit-pratap merged commit 2f4a270 into DynamoDS:master Jun 27, 2022
@aparajit-pratap aparajit-pratap deleted the fixDictValues branch June 27, 2022 17:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants