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-5369: variable number of input ports for Watch3D nodes #13896

Merged
merged 8 commits into from
May 4, 2023

Conversation

LongNguyenP
Copy link
Contributor

@LongNguyenP LongNguyenP commented Apr 12, 2023

Purpose

This PR implements DYN-5369 (Allowing the Watch3D node to have variable number of input ports)

Declarations

Check these if you believe they are true

  • 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

image

This PR makes the Watch3D node into a VariableInputNode. This allows the user to avoid using the List.Create.

Reviewers

FYIs

@LongNguyenP LongNguyenP changed the title DYN-5369 DYN-5369-2 Apr 12, 2023
@LongNguyenP
Copy link
Contributor Author

@mjkkirschner
After some thoughts, I think the API breaking change problem does not exist. It is true that Watch3d now inherits from VariableInputNode and needs to implement the two abstract method (and it already does), but this will not cause any problem for any existing third-party nodes that inherit from Watch3d because the two abstract methods have already been implemented in the Watch3d. These third-party nodes should just work as they are. Would be great if you can confirm whether I am correct here.

@mjkkirschner
Copy link
Member

Hi @LongNguyenP,

I tested your question - by creating a custom watch3d node inheriting from Watch3D referencing 2.18 binaries, and then loaded it into dynamo built against your branch.

It did load correctly, and the UI was updated to include the new buttons.

the docs do mention your question as well:

Introducing a new base class

So long as it does not introduce any new abstract members or change the semantics or behavior of existing members, a type can be introduced into a hierarchy between two existing types. For example, between .NET Framework 1.1 and .NET Framework 2.0, we introduced DbConnection as a new base class for SqlConnection which previously derived from Component.

and indicate that it IS an API break... but given my test, I am not sure under what circumstances, maybe only if the type does not override these methods, I am not sure.

@pinzart90 any thoughts on this? I am inclined to overlook it because I doubt watch3d is inherited frequently.

Copy link
Member

@mjkkirschner mjkkirschner left a comment

Choose a reason for hiding this comment

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

1.A few questions and
2. I think this needs tests for the new methods / interactions.

src/DynamoCoreWpf/Controls/DynamoNodeButton.cs Outdated Show resolved Hide resolved
src/DynamoCoreWpf/Controls/DynamoNodeButton.cs Outdated Show resolved Hide resolved
@@ -171,34 +171,10 @@ public void SetWatchSize(double w, double h)

public override IEnumerable<AssociativeNode> BuildOutputAst(List<AssociativeNode> inputAstNodes)
{
if (IsPartiallyApplied)
Copy link
Member

Choose a reason for hiding this comment

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

interesting, this seems like it could break some graphs, what did watch3d do when partially applied? Did it actually work?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am not sure what IsPartiallyApplied mean? (I am still quite ignorant of many of Dynamo's inner working details) Does this mean the node will output a Function when the input is a Function? If so, this behavior is still maintined in this PR

image

Copy link
Member

Choose a reason for hiding this comment

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

kind of, partially applied is a functional programming term - it means that a function has been created with some input parameters set and others still free.

Can you please confirm what happened before and after your changes if you actually invoke the function on some input, you can use map node - I don't think this is so important but honestly I have no idea what the behavior was, so let's see...

My feeling is that it used to just return the input object, lets see if it still does that?

Copy link
Member

Choose a reason for hiding this comment

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

your screenshot is not what I mean -
we want the output of the Watch3D node to be a function - or rather, I am trying to understand if that used to work and now it is broken - which I am guessing is the case because of the code you have removed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@mjkkirschner You are right, in the current master branch the Watch3D node will output a function (rather than "null) if the only-input port is free.

So looks like this PR will break any existing graph that relies on this function-output behavior, even thought I doubt if anyone would use Watch3D in such a way.

src/Libraries/Watch3DNodeModels/Watch3D.cs Outdated Show resolved Hide resolved
new DynamoNodeButton(nodeView.ViewModel.NodeModel, "AddInPort")
{
Content = "+",
Style = (Style)SharedDictionaryManager.DynamoModernDictionary["AddRemoveButton"]
Copy link
Member

Choose a reason for hiding this comment

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

is it possible to use nameof or some other method to have this fail at compile time if the key is changed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am not sure if nameof is possible here. This part of the code is based on the NodeViewCustomization of the VariableInputNode and there the name "AddInPort" etc.. were actually hardcoded

Copy link
Member

Choose a reason for hiding this comment

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

could you pull all of these out into consts?

@mjkkirschner
Copy link
Member

looks like a bunch of failing tests in last build.

@LongNguyenP
Copy link
Contributor Author

Yep it seems that in this PR, Dyn files that contain Watch3D node saved in previous version did not open correctly. Looks like the deseiralization method of the VariableInputNode is not compatible with existing Watch3d implementation Investigating now. L

@pinzart90
Copy link
Contributor

pinzart90 commented Apr 17, 2023

Hi @LongNguyenP,

I tested your question - by creating a custom watch3d node inheriting from Watch3D referencing 2.18 binaries, and then loaded it into dynamo built against your branch.

It did load correctly, and the UI was updated to include the new buttons.

the docs do mention your question as well:

Introducing a new base class

So long as it does not introduce any new abstract members or change the semantics or behavior of existing members, a type can be introduced into a hierarchy between two existing types. For example, between .NET Framework 1.1 and .NET Framework 2.0, we introduced DbConnection as a new base class for SqlConnection which previously derived from Component.

and indicate that it IS an API break... but given my test, I am not sure under what circumstances, maybe only if the type does not override these methods, I am not sure.

@pinzart90 any thoughts on this? I am inclined to overlook it because I doubt watch3d is inherited frequently.

I do not think there will be any binary compatibility breaking changes or source code breaking changes as long as the Watch3D class implements all the abstract methods of the new intermediary base class VariableInputNode
There might be Behavioral breaking changes if the new Intermediary base class changes the overrides of the NodeModel virtual methods in unexpected ways

@LongNguyenP
Copy link
Contributor Author

Hi @LongNguyenP,
I tested your question - by creating a custom watch3d node inheriting from Watch3D referencing 2.18 binaries, and then loaded it into dynamo built against your branch.
It did load correctly, and the UI was updated to include the new buttons.
the docs do mention your question as well:

Introducing a new base class

So long as it does not introduce any new abstract members or change the semantics or behavior of existing members, a type can be introduced into a hierarchy between two existing types. For example, between .NET Framework 1.1 and .NET Framework 2.0, we introduced DbConnection as a new base class for SqlConnection which previously derived from Component.

and indicate that it IS an API break... but given my test, I am not sure under what circumstances, maybe only if the type does not override these methods, I am not sure.
@pinzart90 any thoughts on this? I am inclined to overlook it because I doubt watch3d is inherited frequently.

I do not think there will be any binary compatibility breaking changes or source code breaking changes as long as the Watch3D class implements all the abstract methods of the new intermediary base class VariableInputNode There might be Behavioral breaking changes if the new Intermediary base class changes the overrides of the NodeModel virtual methods in unexpected ways

Great. Thanks for confirming

@mjkkirschner
Copy link
Member

@LongNguyenP please don't update these xml files unless you have a good reason - the fact that you need to illustrates that legacy user graphs that were saved in .xml will potentially be broken. Have you been able to find out why the failures are occurring with xml deserialization.

We still need to support xml deserialization!

@LongNguyenP
Copy link
Contributor Author

We still need to support xml deserialization!

Understood. I am digging deeper in the issue with XML now.en
BTW. Do you remember at which point Dynamo swtiched from XML to JSON dyn files?

@LongNguyenP
Copy link
Contributor Author

Ok I think I have got it. It was indeed because the XML deseiralization of the VariableInputNode (which Watch3D now inherits) was expecting a an XML attribute called "inputcount", which did not exist in the existing Watch3D's XML serialized data.

I have addressed this and the tests now pass on my local machine. Let's see they will pass on Jenkins too.

@LongNguyenP
Copy link
Contributor Author

LongNguyenP commented Apr 18, 2023

Looks like all tests now pass on Jenkins!

Except CoreUserInterfaceTests.WorkspaceContextMenu_TestIfOpenOnRightClick. However, this test passes on my machine and does not seem to have anything to do with Watch3d. maybe just due to Jenkins . Investigating...

@LongNguyenP
Copy link
Contributor Author

All tests have passed now !

@mjkkirschner
Copy link
Member

We still need to support xml deserialization!

Understood. I am digging deeper in the issue with XML now.en BTW. Do you remember at which point Dynamo swtiched from XML to JSON dyn files?

this happened when we moved from dynamo 1.x to 2.x

@mjkkirschner
Copy link
Member

I also notice the watch3d node looks a bit different -FYI @Jingyi-Wen for review.

@mjkkirschner
Copy link
Member

Looks like all tests now pass on Jenkins!

Except CoreUserInterfaceTests.WorkspaceContextMenu_TestIfOpenOnRightClick. However, this test passes on my machine and does not seem to have anything to do with Watch3d. maybe just due to Jenkins . Investigating...

yeah this test is just flaky, don't worry about that one, I think it's marked failure now.

@mjkkirschner mjkkirschner requested a review from Jingyi-Wen April 21, 2023 16:13
@LongNguyenP
Copy link
Contributor Author

I also notice the watch3d node looks a bit different -FYI @Jingyi-Wen for review.

We made some change to the UI/UX design. We wanted to use per-port context menu for add and removing ports (instead of using the plus or minus button). This way the user can insert a new node in-between existing node and remove a node in the middle if needed. But this require significantly more work so @saintentropy and I thought we should just keep using the plus and minus buttons for now and make another task for the per-port context menu later (I believe this won't break any existing graph that uses plus and minus buttons)

@mjkkirschner
Copy link
Member

I also notice the watch3d node looks a bit different -FYI @Jingyi-Wen for review.

We made some change to the UI/UX design. We wanted to use per-port context menu for add and removing ports (instead of using the plus or minus button). This way the user can insert a new node in-between existing node and remove a node in the middle if needed. But this require significantly more work so @saintentropy and I thought we should just keep using the plus and minus buttons for now and make another task for the per-port context menu later (I believe this won't break any existing graph that uses plus and minus buttons)

thanks @LongNguyenP - last thing can you please see my clarifying comments on the partial function application (function passing) and check the behavior before and after.

@aparajit-pratap
Copy link
Contributor

@LongNguyenP please give an appropriately descriptive title to your Dynamo PRs, other than just the JIRA ticket number. It helps reviewers both internally and externally what the overall intention of the change is.

@LongNguyenP LongNguyenP changed the title DYN-5369-2 DYN-5369: variable number of input ports for Watch3D nodes Apr 27, 2023
@LongNguyenP LongNguyenP merged commit 258cdaa into master May 4, 2023
@LongNguyenP LongNguyenP deleted the DYN-5369-2 branch May 4, 2023 02:37
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