From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

LabVIEW Idea Exchange

cancel
Showing results for 
Search instead for 
Did you mean: 
JackDunaway

Fluent Interfaces with Method Chaining for Objects (especially .NET!)

Status: New

The concept of fluent interfaces using method chaining applied to a LabVIEW block diagram would be awesome!

 

When calling .NET libraries from LabVIEW, block diagrams explode horizontally - the aspect ratio of the diagram can easily push 5:1 or worse (it's 10:1 in the example below). Some Method Chaining syntactical sugar would yield a more space-efficient-and-readable 4:3 to 16:9 or so.

 

Property Chaining is already well-established in LabVIEW - let's get us some Method Chaining!

 

LabVIEW-Idex-Proposed-Fluent-Interface-with-Method-Chaining.png

 

See the first comment for footnotes...

18 Comments
JackDunaway
Trusted Enthusiast

A few footnotes:

 

  1. Although this request is specifically within the context of .NET programming (which tends to be methods-heavy, compared to properties-heavy VI Server), this could also apply to VI Server objects.
  2. In the example above, the methods are even chained to the constructor! <thumbsup />
  3. Note the 2px border between distinct methods - is there a better way to visually distinguish? Maybe 3px? Maybe, grey the background of the method name?
  4. DARE WE INTERSPERSE Property Chaining with Method Chaining? How cool would that be?! The syntax of traditional text-based OO languages do not lend themselves to this ability, but LabVIEW is perfectly equipped to handle this! (Am I crazy? Or just might this work?)
SteenSchmidt
Trusted Enthusiast

Really good suggestion. I've actually occasionally attempted to drag an additional method out of the node just to realize "right, I can't do that" 🙂

 

This would be great for all methods, probably only sometimes beneficial for VI Server but definetely a space saver for ActiveX and other object heavy APIs. The suggestion would due some good in distinguishing which object a particular method node operates on. In an ideal scenario we'd have one method node per object (probably wouldn't in practice, but close).

 

Kudos,

Steen

CLA, CTA, CLED & LabVIEW Champion
Brian_Powell
Active Participant

I'd like to generalize this idea, if only for the sake of understanding the root concern, so here are some probing questions...

 

How is this different than five VIs spread left to right called one after another?  Is it purely a concern of the number of horizontal pixels, or would you like to see a way of calling a sequence of VIs that is naturally top to bottom?  (Without backwards-flowing wires.)

 

What if it were five Express VIs (in their expanded state), or any VI with "View as Icon" turned off?  Do you have the same concern about the number of horizontal pixels for diagrams with those nodes?  Would you like to see a similar top-to-bottom solution for those?

 

In the existing Invoke Node, is "Name Format >> No Names" sufficient for addressing the issue?

 

What if the Invoke Nodes looked (or could be configured to look) more like VIs?  Would you still want to be able to chain them and stack them top to bottom?

X.
Trusted Enthusiast
Trusted Enthusiast

<joke> That's what the stacked sequence structure is for! </joke>

JackDunaway
Trusted Enthusiast

Brian, great questions.

 

How is this different than five VIs spread left to right called one after another? ...

What if the Invoke Nodes looked (or could be configured to look) more like VIs? VI interfaces are designed with meaningful icons and coherent conpanes. .NET libraries (or any DLL, or even VI Server libraries) were not designed with this type of graphical interface in mind. Attempting to VI-a-tize or iconify these functions feels like it could be forced or unintuitive - I'm open to exploring this, but can't myself think of a better graphical interface (it's already good!).

 

What if it were five Express VIs... Would you like to see a similar top-to-bottom solution for those?

Briefly - no. Method chaining is one of the finer points of syntactical beauty, and takes some synthesis and understanding of which methods are chainable (e.g., no cyclical data dependencies between chained methods). These considerations are typically not high priorites for Express VI users, and I don't know enough about the corpus of Express VIs to know if many (or any) are chainable.

 

In the existing Invoke Node, is "Name Format >> No Names" sufficient for addressing the issue?

I'm fanatical about code clarity and developer-intent transparency, not necessarily BD footprint minification. Optimizing code density is helpful for clarity, yet 'No Names' adds a much greater negative impact by obfuscating than the positive impact of a smaller footprint. (that was my civil, forum response. Authentic answer? OHGODMYEYESTHEYBURNTHEYBURNMAKEITSTOP! and probably some arm flailing and maybe some light jumping 🙂

 

Finally, I'll close with this thought - method chaining already exists in LabVIEW, it's only partially-implemented. That's in the form of Property Chaining. Property Reads/Writes are just wee accessor methods. Problems like the cyclical data dependency of passing errors is already solved through node configuration. Usage patterns of not being able to wire an output of a Property Read under and around to the input of a chained Property Write is already not allowed by the compiler. And finally, Fluent Interfaces is a concept that has been proven in other languages, and is just waiting to make its way in LabVIEW.

JackDunaway
Trusted Enthusiast
Forgive the formatting; posted from mobile 😕
GregR
Active Participant

This has been discussed many times at fairly great length. It may be solvable but it is much more complex than you realize.

 

To accomplish this fluent interfaces in .NET it requires that the class be designed to support chaining. In this form the next operation is invoked on the return value of the previous operation. This is also quite common in non-fluent interfaces because properties or methods naturally return some new object and the user frequently does want to immediately call another property or method on that new object. For LabVIEW this is not the case you showed. It is the case where the return value of a previous method is wired to the reference input of the next node. This is probably as common a construct in LabVIEW diagrams I've seen as the multiple invocation on the same reference case.

 

When you grow a property node to show multiple elements, all operations are invoked on the one reference wired to the header input. I would not call that chaining.

 

However your statement that LabVIEW supports property chaining was entirely correct. In fact we support property chaining in the invoke node. Through the "Browse.." behavior of picking a property/method the user is allowed to "drill into" any property that returns a reference and immediately access a property/method on the new reference. That is chaining and is displayed as a single item in the node whose name uses the dotted syntax (i.e. "QueryCursorEvent.Name"). This syntax makes it clear that the intermediate reference is never needed on the diagram so LabVIEW avoids wrapping the reference in our refnum and the user never has to clean it up. However this syntax also does not allow for parameters being passed to the intermediate invocations. Thus the items being chained through are limited to be properties only. For the invoke node that means it can chain through an arbitrary number of properties as long as it ends in a method and the user can then access all parameters of that method.

 

Do you want chaining, multiple invocation, or both? What syntax should be used that allows for parameters but makes it clear whether subsequent calls are on the original reference or on the returned reference of the previous invocation?

JackDunaway
Trusted Enthusiast

>> For LabVIEW this is not the case you showed

 

#ThereIFixedIt -- I think we would both agree that this is now a pure example of Method Chaining. Smiley Happy

 

Method-Chaining

 

In the original example, the slight wiring difference showed subsequent methods being invoked directly on the Parent object, but in this example, subsequent methods are acting on the "this" object returned by the method. 

 

And to be clear, both the original example and this example are functionally equivalent in LabVIEW -- from the point of view from my abstraction layer 🙂

 

I can't find a canonical definition for "Multiple Invocation", but from the context, I'm assuming it means this: invoking multiple methods on an object in succession. (Is that right?)

 

>> Do you want chaining, multiple invocation, or both?

 

I'm asking for fluent interfaces 🙂 But that's not even explicitly true, because that's just my concrete implementation of what I'm *reeeaally* asking for: block diagram readability when programming .NET in LabVIEW.

 

>> What syntax should be used that allows for parameters but makes it clear whether subsequent calls are on the original reference or on the returned reference of the previous invocation?

 

It feels like one caveat we must impose on this feature in LabVIEW is that subsequent methods must always act on the parent object - otherwise method chaining could get *quite* confusing if subsequent methods are all acting on different object types. (Note that the yellow banner on the node intuitively suggests this already - all the invocations below that banner will happen on the object in the yellow banner). For this reason, it probably means I'm more asking for "multiple invocation" than "method chaining", yet for the reason below, "method chaining" may be defined differently LabVIEW than C#.

 

It's arguable that every Invoke Node in LabVIEW already is equipped for chaining because it returns the parent object in the upper-right "reference out" output terminal. This is a language feature of LabVIEW that feels like it's almost equivalent to returning "this" object in C#, a requirement in C# for example that's required if you want to make an object chainable. I think LabVIEW is unique here, in that even if the .NET library developer did not set up the methods to be chainable, they're still inherently chainable by LabVIEW's definition (again, given, no cyclical data dependencies) (and by chainable, maybe multiple invocation is a better term). That's because LabVIEW has a slightly different defintion of "method chaining" to mean "always acts on the parent object".

JackDunaway
Trusted Enthusiast

One final thought to demonstrate that the Fluent Interface implementation in LabVIEW probably has a slightly different definition than the Fluent Interface with Method Chaining in a traditional .NET language -- check out the original example screenshot in the "Proposed: Fluent Interfaces with Method Chaining" frame -- notice that the output object references from methods "WithFilePath", "WithKey" and "WithBucketName" are unwired and unused. Even though the .NET developer has created these methods to be chainable using the explicit facility "return this;", in our realm of inherently-chainable LabVIEW syntax, the return type is unused and unneeded in LabVIEW.

GregR
Active Participant

The wiki page you referenced takes a rather strict definition of fluent programming. It asserts that "the new context is equivalent to the last context". This fits well with your suggested LabVIEW functionality of "subsequent methods must always act on the parent object." However the general method chaining ability in .NET is not restricted to this definition. It is common for .NET APIs to assume that chaining can be done on different contexts. Many would consider Linq as a prime example of fluent programming in .NET. In the Linq statement "list.OfType<Person>().Select(p => p.FirstName).Distinct().OrderBy(n => n).Take(10)" each method is invoked on a different object, many of which have different types.

 

If we say that .NET classes are divided into 3 categories:

  1. classes not designed for chaining
  2. fluent classes (chaining on same object)
  3. classes designed for heterogeneous chaining

Your suggestion gives LabVIEW a better syntax for #1 and #2. The other style would give the better syntax for #2 and #3. It seems to me that giving the better syntax to the thing that has a better syntax in .NET is more likely to satisfy your goal to improve "block diagram readability when programming .NET in LabVIEW".