maestro icon indicating copy to clipboard operation
maestro copied to clipboard

Load and Unload Statement

Open CThuleHansen opened this issue 4 years ago • 5 comments

The load statement is for loading interpreter plugins, and unload is for unloading them. For example:

FMI2 tankcontroller = load("FMI2", "{8c4e810f-3df3-4a00-8276-176fa3c9f000}", "src/test/resources/watertankcontroller-c.fmu");```
unload(tankcontroller);

where the interpreter plugin FMI2 is loaded with two construction(?) parameters: "{8c4e810f-3df3-4a00-8276-176fa3c9f000}" and `"src/test/resources/watertankcontroller-c.fmu".

Loading and Unloading is currently treated as a special case in the parser, lexer and interpreter.

Interpreter Plugins provide MaBL modules with their functions, i.e.:

module FMI2 {
	FMI2Component instantiate(string name, bool logging);
 	void freeInstance(FMI2Component comp);
}

For the following discussion points, please keep the future typechecker in mind as well.

Discussion 1: Should we turn loading and unloading into regular method calls?

I am actually leaning towards no, as these are simply special cases, similar to constructor and destructor in C++, java etc.

TBD: Copy nicks input in here

Discussion 2: No way of expressing the load parameters (constructor parameters) and unload functions.

We are closing in on functions such as constructor and destructor. But how should we express these?

1. Constructor as keyword, implicit destructor

module FMI2 {
        constructor(string guid, string path)
	FMI2Component instantiate(string name, bool logging);
 	void freeInstance(FMI2Component comp);
}

2. As part of the module, implicit destructor

module FMI2(string guide, string path) {
	FMI2Component instantiate(string name, bool logging);
 	void freeInstance(FMI2Component comp);
}

3. As seperate construction module, implicit destructor

module InterpreterPluginConstructors {
FMI2 createFMI2(string guid, string path);
}

**4. Suggestions?**

**My favourite**
I am in favor of 2, as module is already a special case and we do not need to add an extra `constructor` keyword.
Next in line is 3, but I like the constructor being with the module

**Tagging for input**
@nickbattle @lausdahl 

CThuleHansen avatar Jun 19 '20 22:06 CThuleHansen

So as a general principle, I would say that special cases are best avoided but they sometimes can't be avoided! I would just point out that you can have a common syntax (ie. not a special case for the parser) with special case handling in the subsequent type checking and interpretation. But if something is genuinely special, it might be better to invent a syntax for it that specifically doesn't look like anything else. Hence the "new name(args)" for OO languages.

The "usual" style is to have constructor(s) declared with the same name as the thing being constructed, without a return type, so:

module FMI2
{
    FMI2(string guid, string path);   -- Note, the return type is implicit

Option 2 does have some appeal, but it limits you to a single constructor, whereas the constructor-in-body style allows for overloading, potentially. Please don't go for option 3 - that is separating the knowledge across multiple locations? That can't be good.

nickbattle avatar Jun 20 '20 08:06 nickbattle

I see the same reasons as you for 2. Wonder if the syntax should be changed as well. Perhaps load(FMI2,...) instead of load(“FMI2”,...). However, the load statement might stick around.

CThuleHansen avatar Jun 20 '20 14:06 CThuleHansen

A comment about the the actual load call. It seems like its being using in two versions currently i.e. the interpreter seems to use the type given as a string to a little more than just determining the type.

FMI2 a = load("FMI2","fmu.fmu",....)
// and
CSV c = load("CSV") // or load("CSV", csv.so")

Here it looks like the argument with type string indicating the type could be better handled by actually having a type in the language that could only represent known types like Javas Class<?>. At least then the load call would only be called with a known type (the type will be used to know what symbols to symlink).

Load Currently we have two types of load. The basic one which we seems to desire (load(TYPE, library)) which is able to without knowing about the library load it using the TYPE info and potentially forwarding stuff to a constructer for the additional arguments. Secondly, we have an FMI case where we load an FMU but where we have additional custom code to handle this. Currently we have custom code in the interpreter to load FMUs. However, we should handle this better by providing a standard load that looked like

//            load(TYPE, <library name>, constructor args)
FMI2 a = load(FMI2, "Fmu2Loader", "path/to/fmu.fmu",extra args)

Then we could push the custom code out of the interpreter and into an external library and make it work for FMI similar to other libraries. With the hope that loading could then be the same both in the interpreter and in the native implementation. The idea is here that the Fmu2Loader would have the same interface as an FMU but the constructor would be used to do the custom tasks and then forward the remaining work to the FMU and return that.

lausdahl avatar Jun 29 '20 13:06 lausdahl

I am now beginning on the typechecker and obviously encountering this issue. @lausdahl I guess the purpose of having an explicit library name is to provide different backends for providing an FMI2 module, so in some sense it is polymorphism. However, in some cases it seems strange to have this argument, as there will typically only be one. load(DataWriter,"dataWriter") Are you thinking of encoding i.e. distributed FMU here?

CThuleHansen avatar Nov 08 '20 13:11 CThuleHansen

So we discussed this today and here follows some comments: The load call is related to the runtime. Thus, load(FMI2,"FMI2Loader", varargs) will result in the runtime looking for a function called FMI2Loader. This is a way to implement i.e. distributed FMU, by having a different loader but the same interface load(FMI2,"FMI2DistributedLoader", varargs)

CThuleHansen avatar Nov 18 '20 10:11 CThuleHansen