Modelica_DeviceDrivers icon indicating copy to clipboard operation
Modelica_DeviceDrivers copied to clipboard

Modelica compatibility: Construction of external objects is not allowed in records

Open tbeu opened this issue 8 years ago • 23 comments

As @sjoelund reported: External objects are not allowed in records

[HardwareIO.mo:9:5-31:21:writable] Error: Ignoring record component:
  ExternalObject Modelica_DeviceDrivers.HardwareIO.Comedi dh;
when building record the constructor. Records are allowed to contain only components of basic types, arrays of basic types or other records.

tbeu avatar Sep 10 '15 11:09 tbeu

Hm, the restrictions imposed on external objects seem quite arbitrarily to me. Things should compose in a language. It seems odd to me that this would not be allowed and I think it can only be indirectly deduced from the MLS from the sentence that restricts the elements of records to "only contain components of specialized class record and type". Is there some more explicit reasoning why it should be not allowed?

bernhard-thiele avatar Sep 10 '15 15:09 bernhard-thiele

I guess records came first and then external objects. But not sure at all. What do you suggest?

  • Remove comedi.
  • Fix comedi.
  • Make a MLS proposal to change records.

tbeu avatar Sep 11 '15 07:09 tbeu

The reason is that only external object constructors are allowed to return external objects, in order to disallow any function except constructors to create new external objects (so all constructed objects can be destructed later on).

sjoelund avatar Sep 11 '15 07:09 sjoelund

What if is not considered as constructor but only has handle/void* pointer for the external object?

tbeu avatar Sep 11 '15 08:09 tbeu

There is no such thing as a reference (alias) to external object in Modelica :( And external functions returning Integer are not large enough to hold a void* either.

sjoelund avatar Sep 11 '15 08:09 sjoelund

There is no such thing as a reference (alias) to external object in Modelica.

Do you think this should be improved in MLS?

tbeu avatar Sep 11 '15 08:09 tbeu

I think the only reason to allow aliases to external objects would be in order to make connection sets involving external objects (to propagate them).

sjoelund avatar Sep 11 '15 08:09 sjoelund

Which is the other issue #54.

tbeu avatar Sep 11 '15 08:09 tbeu

People actually misused Integer to hold void*. That worked fine as long as Dymola code was 32 bit. Now, we still could have a hack using "doubles" to hold a reference or misuse an Integer array. But having a concept like external objects and resorting to such workarounds makes me scream.

I'm not sure whether they even thought on external objects when restricting the valid elements for records. I would propose to change the specification since I don't see any reason why allowing it would make problems. The external object is created by its own constructor, so constructing and destructing objects should be perfectly fine from my understanding.

bernhard-thiele avatar Sep 11 '15 08:09 bernhard-thiele

We didn't restrict the valid elements for records: we restricted where an external object can be assigned. They are assign once (at initialization or function entry). This was done for a good reason (some tools did not call the destructor, or called it twice if weird things were done with external objects).

sjoelund avatar Sep 11 '15 08:09 sjoelund

A constructed external object is a void* pointer that only can passed to external functions. Why should it be not possible to pass it to records or connectors? I agree with @bernhard-thiele here that this should be allowed.

tbeu avatar Sep 11 '15 08:09 tbeu

You can pass it to records, sure. But the record is not allowed to return it.

sjoelund avatar Sep 11 '15 08:09 sjoelund

I see, finally. Constructing the ext. obj. in the record really is a bad idea.

tbeu avatar Sep 11 '15 08:09 tbeu

I don't see it. Any example where things would go wrong?

bernhard-thiele avatar Sep 11 '15 09:09 bernhard-thiele

How would you destrcut the ext. obj. that was constructed within the record? There is no such thing as a record dtor.

tbeu avatar Sep 11 '15 09:09 tbeu

That's actually not the problem either. The problematic use cases might not exist in this library at all.

sjoelund avatar Sep 11 '15 09:09 sjoelund

I don't know how external objects are implemented in Dymola or OpenModelica. But a first idea would be to keep track at initialization whenever an external object is generated and add a callback to the destructor in a list like structure. If simulation finishes just iterate over the list and call the destructors.

bernhard-thiele avatar Sep 11 '15 09:09 bernhard-thiele

It is not that simple: you can create external objects that only live locally in a function call.

sjoelund avatar Sep 11 '15 09:09 sjoelund

Ok. That would need to be handled as a special case, similar to how the MLS proposes it:

"External objects may be a protected component (or part of one) in a function. The constructor is in that case called at the start of the function call, and the destructor when the function returns, or when recovering from errors in the function."

But what are the problematic cases that you think of?

bernhard-thiele avatar Sep 11 '15 09:09 bernhard-thiele

If you allow aliases, you cannot do that. Because there might be another live version of the same external object somewhere. And you could do things like alias an external object, destruct the object and return the alias to the new loose pointer.

sjoelund avatar Sep 11 '15 09:09 sjoelund

Do you mean alias in the sense of

MyExternalObject obj = MyExternObject();
MyExternalObject alias = obj;

That wouldn't change anything. At simulation end or at simulation failure I would still just go through my list of destructors and call them. I'm trying to think of a situation in a Modelica simulation in which one alias could live longer than another, but since there is no dynamic creation of objects during runtime (except for scope restricted function calls) I can't think of a problematic case. Note that "It is not legal to call explicitly the constructor and destructor functions".

bernhard-thiele avatar Sep 11 '15 09:09 bernhard-thiele

Perhaps the alias was only used during initialization and then it was decided it could be removed?

sjoelund avatar Sep 11 '15 09:09 sjoelund

Hm, this sounds like a tool optimization to look for variables that are only used at initialization time and discard them. If that optimization is performed, a tool might need to do additional checks for external objects. But this is an optimization issue and also seems orthogonal to allowing external objects as elements of records (as soon as you do that optimization you have to check for alias variables anyway).

From a semantics point of view it is not possible to declare a variable that can be only accessed during initialization. If a variable is declared once, it is potentially accessible during the whole simulation.

bernhard-thiele avatar Sep 11 '15 09:09 bernhard-thiele