View Issue Details

IDProjectCategoryView StatusLast Update
000857410000-003: Address SpaceSpecpublic2024-05-21 17:00
ReporterBjarneBostrom Assigned ToJeff Harding  
PrioritynormalSeveritymajorReproducibilityalways
Status assignedResolutionfixed 
Product Version1.05.01 
Fixed in Version1.05.04 RC1 
Summary0008574: An override of a Method InstanceDeclaration shouldn't change InputArguments, the spec shouldn't allow this
Description

Probably too late to change this, but anyway..

https://reference.opcfoundation.org/Core/Part3/v105/docs/4.5.3 says:
"
This standard allows subtyping of type definitions. The subtyping rules are defined in Clause 6. Subtyping of ObjectTypesand VariableTypesallows:

Clientsthat only know the supertype to handle an instance of the subtype as if it were an instance of the supertype;
instances of the supertype to be replaced by instances of the subtype;
specialised types that inherit common characteristics of the base type.

"
However, https://reference.opcfoundation.org/Core/Part3/v105/docs/6.3.3.3 says:
"
A subtype shall not override an argument of its supertype’s Method InstanceDeclaration whichis defined with a concreteDataType. Method arguments defined with an abstractDataType may be overridden. A subtype shall not remove an argument of its supertype’s Method InstanceDeclaration. A subtype shall not add mandatory arguments however it may append optional arguments after all existing arguments of the supertype’s Method InstanceDeclaration.
"
These 2 rules conflict each-others.
https://reference.opcfoundation.org/Core/Part3/v104/docs/6.3.3.3 doesn't have the text, so I assume this was even added in 1.05, why?

Now there is a problem because Machinery companion spec has already used this rule, https://reference.opcfoundation.org/Machinery/Result/v100/docs/7.2 Defines:
"
7.2 ResultTransferType ObjectType Definition
7.2.1 Overview

This ObjectTypeis a subtype of the 0:TemporaryFileTransferTypedefined in OPC 10000-20and is used to transfer result data as a file.

The ResultTransferTypeoverwrites the Method GenerateFileForReadto specify the concrete type of the generateOptions Argument of the Method. It does not specialize the GenerateFileForWrite Methodof the base type as results are supposed to be only generated by the Server, not received.

"
OK, the more problematic thing is that the TemporaryFileTRansferType itself was modeled assuming this rule exists, https://reference.opcfoundation.org/Core/Part5/v104/docs/C.4.3 "C.4.3 GenerateFileForRead" defined that this subtyping should happen:
"
generateOptions

The optional parameter can be used to specify server specific file generation options. To allow such options, the Servershall specify a concrete DataTypein the Argument Structurefor this argument in the instance of the Method.

If the DataTypeis BaseDataType, the Client shall pass Null for this argument.

Examples for concrete DataTypes are

OptionsSetUsed to provide a bit mask for file content selection

String Can be used to provide a string filter or a regular expression

StructureCan be used to provide a structure with create settings e.g. to create a report

EnumerationCan be used to provide a list of options
"

Basically this type is unmodellable in an object oriented language that enforces the https://en.wikipedia.org/wiki/Liskov_substitution_principle, e.g. Java for myself. Basically it could be argued that what Liskov means, but basically think as the first rule ("Clientsthat only know the supertype to handle an instance of the subtype as if it were an instance of the supertype").

In Java, it is not possible to change the "method signature" when doing an override. The input arguments are part of the signature, thus it is not possible to change them. The output parameter could be a subtype of the original output parameter (this was also used in the OPC UA AutoID companion spec, which worked). It is possible to make an overload, i.e. method with the same name, but different signature, but that is basically a completely new method, it would not be callable by a "supertype-client". Thus, due to "Clientsthat only know the supertype to handle an instance of the subtype as if it were an instance of the supertype", it should also be a thing in OPC UA that the signature shouldn't be able to be changed. Overloads could be thing, but not override like this. Thus, the type shall always have a Method with the original signature, it cannot be removed by a subtype.

Not sure what could be done to this. It is probably too late to change the TemporaryFileTransferType. Hopefully other companion specifications wont adopt this "feature" as it limits what SDKs can work with them. OK, probably this can be implemented via some trick, but the method is uncallable purely using supertype information (which one should be able to do using the rule "Clientsthat only know the supertype to handle an instance of the subtype as if it were an instance of the supertype"). So it basically cannot be modelled like "normal types" can be (I develop the Prosys OPC UA SDK for Java, I should note that we make Java types based on OPC UA types via our Codegen tool).

TagsNo tags attached.
Commit Version
Fix Due Date

Activities

BjarneBostrom

2023-01-10 08:12

reporter   ~0018448

Some extra notes that I wrote to Teams after this:

[Yesterday 11:47 AM] Bjarne Boström (Guest)

Thus what our Codegen does cannot be compiled for https://reference.opcfoundation.org/Machinery/Result/v100/docs/7.2 OK, an overload (not override) would be fine (though the original method would still exist). However the Machinery Result model specifically says "The ResultTransferTypeoverwrites the Method GenerateFileForReadto specify the concrete type of the generateOptions Argument of the Method."
​[Yesterday 11:48 AM] Bjarne Boström (Guest)
This is because the core spec says to do that, but in my opinion this should not be allowed. Yes, I can technically "fix" this in our Codegen by faking that the override never took place (i.e. keeping the parameter as "Object" as our BaseDataType mapping is), but then there wasn't any reason to do so in the first place.
​[Yesterday 11:49 AM] Bjarne Boström (Guest)
i.e. once a Method has been defined in a TypeDefinition, it can never be removed nor the inputs altered
​[Yesterday 11:52 AM] Bjarne Boström (Guest)

Thus some of this must be done:

  1. Remove the clients-can-use-supertype part from spec (as it wont apply, plus there is other breakages of this as well with other subtyping rules)

  2. Remove subtyping of input args (removing TemporaryFileTransferType method)

  3. Do nothing and accept that the Part3 conflicts itself. Probably this is what happens as I do not see 1&2 happening. But regradless I would recommend writing some section that this "feature" shouldn't be used (unless there is no other way).

  4. Something else??

BjarneBostrom

2023-01-10 08:26

reporter   ~0018449

Also one additional note: I'm not sure does OPC UA has Method overloading (method with the same name, but different input paramters) i.e. can one make multiple Methods with the same name and different parameters. Since in the Typespace all BrowsePaths must be unique I assume this is not the case, but in the instances it could be possible. IF both overriding and overloading take place, it is not possible to differentiate is the subtyped method an override or an overload.

Jim Luth

2023-07-25 16:40

administrator   ~0019725

Jim to write note and request feedback.

Jim Luth

2023-07-25 19:21

administrator   ~0019726

Bjarne,

Method overloading is not supported in OPC UA types. OPC UA is not going to change how methods work and will continue to allow derived types to add additional optional parameters to the end of the argument lists. Given that the spec is not going to change you seem to imply that how it works is not sufficiently specified. Please provide proposed enhanced wording to clarify the specification given the functionality will not change.

BjarneBostrom

2023-07-26 07:33

reporter   ~0019727

Hi Jim,

I'll try explain this better, but I'm sort of maybe repeating myself a bit, sorry.

Basically the very fact that OPC UA allows "changing" the signature introduces the concept of method overloading in object-oriented terms, i.e. that is the problem here.

Since OPC UA is basically an object oriented language and the previously mentioned https://reference.opcfoundation.org/Core/Part3/v105/docs/4.5.3 "Clients that only know the supertype to handle an instance of the subtype as if it were an instance of the supertype;" means https://en.wikipedia.org/wiki/Liskov_substitution_principle applies.

That means it is not possible to remove a method signature from a subtype, thus if a subtype "changes" the signature so that a parameter would be subtype, that introduces a new Method and the original remains (!), thus the Method overloading concept is introduced (assuming here the same name was used for the Method as the original).

A client not knowing the subtype would just see the original method ("super type view", the '4.5.3' above) and must be able to call that. Another client seeing the subtype would see 2 methods (the original supertype and the one from the subtype). This is how all object-orientend programming languages work to my knowledge (most of that is from Java though). Typically it is however allowed to change the return type in overriding to be a subtype, as that doesn't break the method contract for "supertype callers", but any changes to input parameters does introduce a new method (and if it is the same name, an overload in Java-terms at least). Only if the input parameters are the same it is an override.

Thus, the OPC UA spec contradicts itself. The same problem does exist when an InstanceDeclaration can change the DataType to a subtype (i.e. users of the original TypeDefinition for that InstanceDeclaration do see the original DataType and as far as I understand per Liskov be allowed to use that). But skipping this here as that has been discussed previously and it is a no can do situation (i.e. the very concept of "VariableTypes" causes the problem I believe, cannot be fixed).

And specifically the problem I have is within Java and our (Prosys OPC UA SDK)
Codegen tool because I basically have to fake each such subtype to remove the subtyping of the method parameter because java enforces Liskov. Or like I could also make this an "overload", but as you said this concept doesn't properly exist in OPC UA before this "maddness" and thus we are not handling it and thus basically for the type to work at all the easiest solution is to just correct the subtype to have the same signature (as it should have been).

The Java part can be ignored as that is like "my problem", but using purely the spec itself it both allows and disallows changing the signature and while not allowing overloading it is just a contradiction I wish could be solved somehow.. but as said, I do not see TemporaryFileTransferType changing. But maybe it could just be noted "sorry we made a mistake, do not make anymore types like this" or something.

BjarneBostrom

2023-07-26 08:41

reporter   ~0019728

Trying to explain also with more simple terms.

Lets say we have types A and B and B is subtype of A.

Let A have method foo(Number).

Using normal object oriented inheriting rules and https://reference.opcfoundation.org/Core/Part3/v105/docs/4.5.3 B shall have also method foo(Number), otherwise the listed rules (and Liskov) are broken and B cannot be used as A.

Then https://reference.opcfoundation.org/Core/Part3/v105/docs/6.3.3.3 "magically" allows an "override" of foo(Number) with e.g. foo(Int32) on B. But that cannot be, as it is not an override, as foo(Number) shall also exist, otherwise clients with "A-only-knowledge" cannot treat B as the A-supertype. Thus, B shall have both foo(Number) and foo(Int32) and the foo(Int32) is an overload, not override.

Thus, a contradiction.

Or do I miss something here?

P.S.
Like yes, in Java one could make B.foo(Number) to throw e.g. DoNotUseException, but that would be bad design typically.

Jim Luth

2023-12-19 17:34

administrator   ~0020535

From an implementation standpoint, the Server must implement the method with the signature of the base type where the method is originally defined (like foo(Number) in A). The contract foo(Number) does not imply the method needs to be able to process all sub-types of Number without Error. The more restricted override in B is allowed so long as the override does not violate the contract in A (i.e. int32 is a valid Number). The method signature is valuable for Clients because it gives a Client better information as to what type of values will likely be accepted by the method and produce a non-error result.

Jeff Harding

2024-05-20 19:03

developer   ~0021204

Added an additional statement to 6.3.3.3 describing what the required behavior of methods with optional arguments that are overridden.

Jim Luth

2024-05-21 16:59

administrator   ~0021224

Still no viable conclusion on what to do here -- deferred to a future release.

Issue History

Date Modified Username Field Change
2023-01-09 08:37 BjarneBostrom New Issue
2023-01-10 08:12 BjarneBostrom Note Added: 0018448
2023-01-10 08:26 BjarneBostrom Note Added: 0018449
2023-06-06 15:50 Jim Luth Assigned To => Jeff Harding
2023-06-06 15:50 Jim Luth Status new => assigned
2023-07-25 16:40 Jim Luth Note Added: 0019725
2023-07-25 19:21 Jim Luth Assigned To Jeff Harding =>
2023-07-25 19:21 Jim Luth Status assigned => feedback
2023-07-25 19:21 Jim Luth Note Added: 0019726
2023-07-26 07:33 BjarneBostrom Note Added: 0019727
2023-07-26 07:33 BjarneBostrom Status feedback => new
2023-07-26 08:41 BjarneBostrom Note Added: 0019728
2023-12-19 17:34 Jim Luth Note Added: 0020535
2023-12-19 17:40 Jim Luth Assigned To => Jeff Harding
2023-12-19 17:40 Jim Luth Status new => assigned
2023-12-19 17:41 Jim Luth Commit Version => 1.05.04 RC
2023-12-19 17:41 Jim Luth Fix Due Date => 2024-01-31
2024-05-20 19:03 Jeff Harding Status assigned => resolved
2024-05-20 19:03 Jeff Harding Resolution open => fixed
2024-05-20 19:03 Jeff Harding Fixed in Version => 1.05.04 RC1
2024-05-20 19:03 Jeff Harding Note Added: 0021204
2024-05-21 16:59 Jim Luth Note Added: 0021224
2024-05-21 16:59 Jim Luth Status resolved => assigned
2024-05-21 17:00 Jim Luth Commit Version 1.05.04 RC =>
2024-05-21 17:00 Jim Luth Fix Due Date 2024-01-31 =>