Opened 9 years ago

Last modified 6 years ago

#3853 new task

Clean up OpenModelica base libraries

Reported by: Rüdiger Franke Owned by: Martin Sjölund
Priority: high Milestone: 2.0.0
Component: MetaModelica Version:
Keywords: Cc: Henning Kiel, Per Östlund, Peter Fritzson

Description

OpenModelica uses its own language and base libraries. Sometimes they appear grown arbitrarily instead of thoroughly designed. This costs a lot of time for looking up and finding out the right functions. Development time could be reduced and code quality increased if there were more common conventions. See three examples for lists, arrays and strings below.

Everyone can remember basic list operations, like map and fold:

  List.fold(List.map(outLocal, BackendVariable.varCref), BaseHashSet.add, HashSet.emptyHashSet());

But OpenModelica works more efficient if people state:

  List.applyAndFold(outLocal, BaseHashSet.add, BackendVariable.varCref, HashSet.emptyHashSet());

See: 9027e889/OMCompiler. Can't combined functions like applyAndFold be hidden from the public interface and used by the translator automatically?

Here is an array example from SimCodeUtil.mo:

  Dangerous.arrayUpdateNoBoundsChecking(simVars, Integer(index),
     simVar::Dangerous.arrayGetNoBoundsChecking(simVars, Integer(index)));

Everyone could immediately grasp what this does if it was formulated like:

  simVars[index] := simVar :: simVars[index];

Does it really pay off in the high-level language MetaModelica to skip the bounds check?

Last but not least strings. One commonly wants to generate a string representation of an object, e.g. for debug logging. Programming languages typically offerer a common concept that applies everywhere, like object.ToString() or to_string(object).

OpenModelica sometimes uses the concept of appending String to the type name and starting with lower case, like intString or realString. This concept is also used in BackendDump.mo, e.g. for BackendDump.equationString or BackendDump.timeEventString.

But there are many other functions that use a different naming that one hardly can remember, mostly in DAEDump.mo, prepending dump or appending Str instead of String or inventing some abbreviations, like:

  DAEDump.dumpOperatorString       --  operatorString
  DAEDump.dumpExtDeclStr           --  externalDeclString
  DAEDump.derivativeCondStr        --  derivativeCondString

It helped a lot if a common concept was used everywhere.

Change History (9)

in reply to:  description comment:1 by Martin Sjölund, 9 years ago

Replying to rfranke:

Can't combined functions like applyAndFold be hidden from the public interface and used by the translator automatically?

No. List.fold and List.map are both in the user libraries and the separate compilation by necessity does not show implementation details. In some instances it is possible to use things like:

BaseHashTable.add(BackendVariable.varCref(v) for v in vars)

But this requires a default start value for add (so it does not work for hashtables and also not when continuing from a different folded value, etc).

Does it really pay off in the high-level language MetaModelica to skip the bounds check?

Yes, the gain is huge in many instances.

comment:2 by Rüdiger Franke, 9 years ago

If MetaModelica requires weired formulations, then there is something wrong with the language design.

Last edited 9 years ago by Rüdiger Franke (previous) (diff)

comment:3 by Adrian Pop, 9 years ago

@rfranke: it should be possible to keep the high level formulations and not use "weird" unsafe constructs if we would have an intermediate language on which to do optimizations, but we don't have it yet. For example this can be optimized in a for loop with no extra allocations:

List.fold(List.map(outLocal, BackendVariable.varCref), BaseHashSet.add, HashSet.emptyHashSet());

These kind of optimizations are applied in Haskell:
http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.104.7401

Another "problem" is that we don't generate machine (less restrictions, more optimizations) code but C.

I agree with you that for now we should improve the homogeneity of the function names and modularization so is easier to find functions because the naming is better.

comment:4 by Rüdiger Franke, 9 years ago

OK, that's a good motivation for an intermediate language. We might focus on this then, instead of attempting to optimize the code by at the price of lost readability.

Version 0, edited 9 years ago by Rüdiger Franke (next)

comment:5 by Rüdiger Franke, 9 years ago

Cc: Henning Kiel added

comment:6 by Per Östlund, 9 years ago

Cc: Per Östlund added

comment:7 by Francesco Casella, 6 years ago

May I suggest to use LLVM as an intermediate language?

comment:8 by Rüdiger Franke, 6 years ago

Cc: Peter Fritzson added

The string issue can be solved now, i.e. may clean up all the legacy string converters. As noted by Peter:

print(anyString(xxxx));

where xxxx - any metaModelica datastructure

comment:9 by Rüdiger Franke, 6 years ago

Well, anyString does not really solve the issue. Imagine you have a DAE.Exp and happen to know that you can get a string representation with ExpressionDump.printExpStr. Then you get, for example:

previous(x[i]) 

Calling anyString for the same expression results in:

DAE.Exp.CALL(path = Absyn.Path.IDENT(name = previous), expLst = {DAE.Exp.CREF(componentRef = DAE.ComponentRef.CREF_IDENT(ident = x, identType = DAE.Type.T_ARRAY(ty = DAE.Type.T_REAL(varLst = {NIL}), dims = {DAE.Dimension.DIM_INTEGER(integer = 10)}), subscriptLst = {DAE.Subscript.INDEX(exp = DAE.Exp.CREF(componentRef = DAE.ComponentRef.CREF_IDENT(ident = i, identType = DAE.Type.T_INTEGER(varLst = {NIL}), subscriptLst = {NIL}), ty = DAE.Type.T_INTEGER(varLst = {NIL})))}), ty = DAE.Type.T_REAL(varLst = {NIL}))}, attr = DAE.CallAttributes.CALL_ATTR(ty = DAE.Type.T_REAL(varLst = {NIL}), tuple_ = 0, builtin = 1, isImpure = 0, isFunctionPointerCall = 0, inlineType = DAE.InlineType.DEFAULT_INLINE(), tailCall = DAE.TailCall.NO_TAIL())) 

MetaModelica is simply lacking a common convention. The new frontend appears to have introduced such a convention by defining functions toString as part of encapsulated uniontype. Modern programming languages allow you to call the human defined string converter for each object in the same way, like object.toString() in Javascript, object.ToString() in C#, or to_string(object) in C++.

Note: See TracTickets for help on using tickets.