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)
comment:1 by , 9 years ago
comment:2 by , 9 years ago
If MetaModelica requires weired formulations, then there is something wrong with the language design.
comment:3 by , 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 , 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.
comment:5 by , 9 years ago
Cc: | added |
---|
comment:6 by , 9 years ago
Cc: | added |
---|
comment:8 by , 6 years ago
Cc: | 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 , 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++.
Replying to rfranke:
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:
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).
Yes, the gain is huge in many instances.