What is the best way to declare a constant into a class that can be redefined - constants

What is in eiffel the best way to have a constant which can be redefined?
class A => color: STRING = "green"
color B inherit A => cannot redefine
while having a function which only returns "green" or "blue" needs the string to be created again, performance problem or doesnt matter?
As far as I understood, the onces cannot be redeclared...

Once features can be redefined as any other features. The example would be
class A feature
color: STRING once Result := "green" end
end
class B inherit A redefine color end feature
color: STRING once Result := "blue" end
end
Also, manifest strings themselves can be defined as once:
class A feature
color: STRING do Result := once "green" end
end
class B inherit A redefine color end feature
color: STRING do Result := once "blue" end
end
The behavior in both cases is identical, so you can even mix both variants. The performance might be different but only marginally. In both cases new strings are not created on every call.

Related

Defining Julia types using macros

Let's say I want to define a series of structs that will be used as parametric types for some other struct later on. For instance, I would like to have something like
abstract type Letter end
struct A <: Letter end
struct B <: Letter end
...etc...
The idea I've had is to define a macro which takes a string of the name of the struct I want to create and defines it as well as some basic methods. I would then execute the macro in a loop for all names and get all my structs defined at compile time. Something like this:
const LETTERS = ["A","B","C","D"]
abstract type Letter end
macro _define_type(ex)
lines = Vector{Expr}()
push!(lines, Meta.parse("export $ex"))
push!(lines, Meta.parse("struct $ex <: Letter end"))
push!(lines, Meta.parse("string(::Type{$ex}) = \"$ex\""))
return Expr(:block,lines...)
end
#_define_type "A"
for ex in LETTERS
#_define_type ex
end
The first way of executing the macro (with a single string) works and does what I want. However, when I execute the macro in a loop it does not. It tells me some variables are declared both as local and global variables.
Can someone explain what is happening? I believe it may be solved by a proper use of esc, but I can't figure out how.
Thanks!
Edit: Thank you all for the amazing responses! Got my code running!
I think this is what you are trying to do:
module MyModule
abstract type Letter end
const LETTERS = ["A", "B", "C", "D"]
for letter in LETTERS
sym = Symbol(letter)
#eval begin
export $sym
struct $sym <: Letter end
Base.string(::Type{$sym}) = $letter
end
end
end
using .MyModule
string(A) # "A"
See the Code Generation section for more details:
https://docs.julialang.org/en/v1/manual/metaprogramming/#Code-Generation
Okay, the problem here is that in Julia for loops introduce a separate, local scope, while struct definitions need to be in the global scope. So your macro fails because it creates struct definitions in the local scope of the for loop.
A way to get around this is to use #eval, to ensure your struct definitions are evaluated in the global scope. In that case, you don't need to create a macro for that, just have a simple loop like this:
abstract type Letter end
const LETTERS = [:A, :B, :C, :D, :E]
for ex in LETTERS
#eval struct $ex <: Letters end
end
You can even put that loop in a function and it will still work. The defined structs can have fields, as #eval covers the entire code block that follows it.
Note that LETTERS must contain symbols rather than strings for this to work correctly. It's easy enough to convert a vector of strings into a vector of symbols using Symbol.(vector_of_strings).
While there are other ways of achieving what you want to do I believe the core issue is understanding the nature of macros. From the docs (emphasis mine):
Macros are necessary because they execute when code is parsed, therefore, macros allow the programmer to generate and include fragments of customized code before the full program is run.
So the macro in your loop does not "see" the values "A", "B", "C" and "D", it sees the expression: ex. To demonstrate this try using #macroexpand:
julia> #macroexpand #_define_type ex
quote
export ex
struct ex <: Main.Letter
#= none:1 =#
end
var"#11#string"(::Main.Type{Main.ex}) = begin
#= none:1 =#
"ex"
end
end
As you can see the actual value of the variable ex does not matter. With this in mind let's look at the actual error you get. You can reproduce it like this:
julia> for ex in ["A"]
struct ex <: Letter
end
end
ERROR: syntax: variable "ex" declared both local and global
Stacktrace:
[1] top-level scope
# REPL[52]:1
You can probably see that this is not what you want, but why this specific error? The reason is that structs are implicitly global while the loop variable is local.
Here is a possible solution that uses a macro that takes a variable number of arguments instead (I also switched to providing the expression directly instead of as a string):
abstract type Letter end
macro _define_types(exprs...)
blocks = map(exprs) do ex
name = string(ex)
quote
export $ex
struct $ex <: Letter end
Base.string(::Type{$ex}) = $name
end
end
Expr(:block, blocks...)
end
#_define_types A
#_define_types B C D

Conditional declaration by array of records

I try to create many components depending on the value of constant elements. These elements are organized in an array of records.
Dymola prints the translation log for the example below:
But I'm sure to use fixed conditions because I only perform allowed operations on constant values.
Here is the simple example of what I wantet to do:
model ConditionalComponent
type Enum = enumeration(one,two,three);
record Tmp
parameter Integer ID;
parameter Boolean active;
end Tmp;
record TmpNamed
parameter Enum name;
extends Tmp;
end TmpNamed;
function reorder
input TmpNamed inp[:];
output Tmp out[size(inp,1)];
algorithm
for elem in inp loop
out[elem.name] := Tmp(elem.ID, elem.active);
end for;
end reorder;
constant TmpNamed testIn[:] = {
TmpNamed(Enum.two,20,true),
TmpNamed(Enum.one,10,true),
TmpNamed(Enum.three,30,true)};
constant Tmp testOut1[:] = reorder({
TmpNamed(Enum.two,20,true),
TmpNamed(Enum.one,10,true),
TmpNamed(Enum.three,30,true)});
constant Tmp testOut2[:] = reorder(testIn);
constant Boolean active1 = testOut1[Enum.one].active;
constant Boolean active2 = testOut2[Enum.one].active;
Real t1=0 if testOut1[Enum.one].active;
//Real t2=0 if testOut2[Enum.one].active;
//Real t3=0 if active1;
//Real t4=0 if active2;
end ConditionalComponent;
The function reorder is intended to ease the management of large lists of named active components. Normally the constant testOut2 is used and created within the package ConditionalComponent. But for testing purposes ConditionalComponent is a model here. Actually I only want to use the line
Real t2=0 if testOut2[choice].active;
parameter Enum choice = Enum.one;
within other components, that have a parameter of type Enum. The declarations for t1, t3, t4 are only some tests that work, depending on what is left uncommented.
For example leaving the declaration for t1 and t3 uncommented works. But if one uses only the declaration for t1, it is not translated by Dymola.
The difference between t1 and t2 is, that the argument for reorder is passed directly or via the constant testIn.
I'm sure, that most parameter and constant prefixes are unnecessary and I tried hard to figure out the problem. But unfortunately I cannot decide whether Dymola is not working correctly or I did something wrong. And I've got no idea how to debug the translation process to figure it out by myself.
Can anyone tell me, what am I doing wrong?
Not something wrong, but it's just currently seen as too complicated and not handled.
A work-around is to split subscripting and element access:
constant Tmp testOut1_one=testOut1[Enum.one];
Real t1=0 if testOut1_one.active;

Matlab: How do I call a function which I have defined within a class?

I'm trying to learn how to use classes in Matlab, having never used them in any language before, so apologies if this is a bit basic.
I have defined a class called car, with the properties of colour, type, serial number and speed, with a function to change the speed.
classdef car <handle
properties
colour
type
speed
end
properties (SetAccess = private)
SerialNumber
end
methods
function faster(obj, v)
obj.speed = obj.speed + v;
end
end
end
In another script I can type
car.colour = "red", and when I disp(car), the class has the property colour with label "red". When I call faster(100) however, instead of setting car.speed=100, it throws the error
Check for missing argument or incorrect argument data type in call to function 'faster'.
I built the class and method using the same sort of code structure as in this question:
https://www.mathworks.com/matlabcentral/answers/395472-how-to-call-a-method-from-a-class-called-a-within-another-method-from-a
where the user seemed to not have the issue I do. I'm not sure where I'm going wrong - my function seems like it should work. Can anybody point me in the right direction?
You need to call the function on the class
myCar = car();
myCar.faster( 10 ); % equivalent to 'faster( myCar, 10 )'
If you hadn't specified the < handle type, you would also need to assign it back to the class, i.e.
myCar = myCar.faster( 10 );
But you don't need this with a handle class.

create enum with MATLAB [duplicate]

Are there enumerated types in MATLAB? If not, what are the alternatives?
Starting from R2010b, MATLAB supports enumerations.
Example from the documentation:
classdef Colors
properties
R = 0;
G = 0;
B = 0;
end
methods
function c = Colors(r, g, b)
c.R = r; c.G = g; c.B = b;
end
end
enumeration
Red (1, 0, 0)
Green (0, 1, 0)
Blue (0, 0, 1)
end
end
You can get some of the functionality with new-style MATLAB classes:
classdef (Sealed) Colors
properties (Constant)
RED = 1;
GREEN = 2;
BLUE = 3;
end
methods (Access = private) % private so that you cant instantiate
function out = Colors
end
end
end
This isn't really a type, but since MATLAB is loosely typed, if you use integers, you can do things that approximate it:
line1 = Colors.RED;
...
if Colors.BLUE == line1
end
In this case, MATLAB "enums" are close to C-style enums - substitute syntax for integers.
With the careful use of static methods, you can even make MATLAB enums approach Ada's in sophistication, but unfortunately with clumsier syntax.
If you want to do something similar to what Marc suggested, you could simply make a structure to represent your enumerated types instead of a whole new class:
colors = struct('RED', 1, 'GREEN', 2, 'BLUE', 3);
One benefit is that you can easily access structures in two different ways. You can specify a field directly using the field name:
a = colors.RED;
or you can use dynamic field names if you have the field name in a string:
a = colors.('RED');
In truth, there are a few benefits to doing what Marc suggested and creating a whole new class to represent an "enum" object:
You can control how the object is modified.
You can keep the definition in one place and easily use it in multiple places.
You can control failures and make them more "graceful", like returning an empty matrix if you try to access a non-existent field (as opposed to throwing an error).
However, if you don't need that sort of complexity and just need to do something quick, a structure is likely the easiest and most straight-forward implementation. It will also work with older versions of MATLAB that don't use the newest OOP framework.
There is actually a keyword in MATLAB R2009b called 'enumeration'. It seems to be undocumented, and I cannot say I know how to use it, but the functionality is probably there.
You can find it in matlabroot\toolbox\distcomp\examples\+examples
classdef(Enumeration) DmatFileMode < int32
enumeration
ReadMode(0)
ReadCompatibilityMode(1)
WriteMode(2)
end
<snip>
end
You could also use Java enum classes from your Matlab code. Define them in Java and put them on your Matlab's javaclasspath.
// Java class definition
package test;
public enum ColorEnum {
RED, GREEN, BLUE
}
You can reference them by name in M-code.
mycolor = test.ColorEnum.RED
if mycolor == test.ColorEnum.RED
disp('got red');
else
disp('got other color');
end
% Use ordinal() to get a primitive you can use in a switch statement
switch mycolor.ordinal
case test.ColorEnum.BLUE.ordinal
disp('blue');
otherwise
disp(sprintf('other color: %s', char(mycolor.toString())))
end
It won't catch comparisons to other types, though. And comparison to string has an odd return size.
>> test.ColorEnum.RED == 'GREEN'
ans =
0
>> test.ColorEnum.RED == 'RED'
ans =
1 1 1
You could make a Matlab class that behaves like a Java's old typesafe enum pattern. A modification of Marc's solution could take it from C-style typedefs to more like Java-style typesafe enums. In this version, the values in the constants are typed Color objects.
The upsides:
The type can be checked (at runtime) by == and other operations to prevent accidental comparison to raw numerics or other types of enums.
You can explicitly check the type of your variables (at runtime).
Values are displayed with readable names instead of the opaque codes.
Operations like mean() and std() that don't make sense on enums are disallowed.
Downsides:
Longer class definition. But, this is all boilerplate, and can be reused for any other enum class, changing just the class name and Constant properties.
These enums cannot be used directly in switch blocks. Need to pop the Code out, which loses some type safety.
Objects will be slower than primitives. Relevant if you're using constants inside loops.
On the whole, I don't know which approach is better. Haven't used either in practice.
classdef (Sealed) Color
%COLOR Example of Java-style typesafe enum for Matlab
properties (Constant)
RED = Color(1, 'RED');
GREEN = Color(2, 'GREEN');
BLUE = Color(3, 'BLUE');
end
properties (SetAccess=private)
% All these properties are immutable.
Code;
Name;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
methods (Access = private)
%private so that you can't instatiate directly
function out = Color(InCode, InName)
out.Code = InCode;
out.Name = InName;
end
end
methods (Static = true)
function needa(obj)
%NEEDA Asserts that obj must be a Color
if ~isa(obj, mfilename)
error('Input must be a %s; got a %s', mfilename, class(obj));
end
end
end
methods (Access = public)
function display(obj)
disp([inputname(1) ' =']);
disp(obj);
end
function disp(obj)
if isscalar(obj)
disp(sprintf('%s: %s (%d)', class(obj), obj.Name, obj.Code));
else
disp(sprintf('%s array: size %s', class(obj), mat2str(size(obj))));
end
end
function out = eq(a, b)
%EQ Basic "type-safe" eq
check_type_safety(a, b);
out = [a.Code] == [b.Code];
end
function [tf,loc] = ismember(a, b)
check_type_safety(a, b);
[tf,loc] = ismember([a.Code], [b.Code]);
end
function check_type_safety(varargin)
%CHECK_TYPE_SAFETY Check that all inputs are of this enum type
for i = 1:nargin
if ~isa(varargin{i}, mfilename)
error('Non-typesafe comparison of %s vs. %s', mfilename, class(varargin{i}));
end
end
end
end
end
Here's a function to exercise it.
function do_stuff_with_color(c)
%DO_STUFF_WITH_COLOR Demo use of the Color typesafe enum
Color.needa(c); % Make sure input was a color
if (c == Color.BLUE)
disp('color was blue');
else
disp('color was not blue');
end
% To work with switch statements, you have to explicitly pop the code out
switch c.Code
case Color.BLUE.Code
disp('blue');
otherwise
disp(sprintf('some other color: %s', c.Name));
end
Example of use:
>> Color.RED == Color.RED
ans =
1
>> Color.RED == 1
??? Error using ==> Color>Color.check_type_safety at 55
Non-typesafe comparison of Color vs. double
Error in ==> Color>Color.eq at 44
check_type_safety(a, b);
>> do_stuff_with_color(Color.BLUE)
color was blue
blue
>> do_stuff_with_color(Color.GREEN)
color was not blue
some other color: GREEN
>> do_stuff_with_color(1+1) % oops - passing the wrong type, should error
??? Error using ==> Color>Color.needa at 26
Input must be a Color; got a double
Error in ==> do_stuff_with_color at 4
Color.needa(c); % Make sure input was a color
>>
A minor quirk in both approaches: the C convention of putting the constant on the left hand of the "==" to prevent bad assignment doesn't help as much here. In Matlab, if you accidentally use "=" with this constant on the LHS, instead of an error, it'll just create a new local struct variable named Colors, and it will mask the enum class.
>> Colors.BLUE = 42
Colors =
BLUE: 42
>> Color.BLUE = 42
Color =
BLUE: 42
>> Color.RED
??? Reference to non-existent field 'RED'.
If you have access to the Statistics Toolbox, you might consider using a categorical object.
After trying out the other suggestions on this page, I landed on Andrew's fully object-oriented approach. Very nice - thanks Andrew.
In case anyone is interested, however, I made (what I think are) some improvements. In particular, I removed the need to double-specify the name of the enum object. The names are now derived using reflection and the metaclass system. Further, the eq() and ismember() functions were re-written to give back properly-shaped return values for matrices of enum objects. And finally, the check_type_safety() function was modified to make it compatible with package directories (e.g. namespaces).
Seems to work nicely, but let me know what you think:
classdef (Sealed) Color
%COLOR Example of Java-style typesafe enum for Matlab
properties (Constant)
RED = Color(1);
GREEN = Color(2);
BLUE = Color(3);
end
methods (Access = private) % private so that you can''t instatiate directly
function out = Color(InCode)
out.Code = InCode;
end
end
% ============================================================================
% Everything from here down is completely boilerplate - no need to change anything.
% ============================================================================
properties (SetAccess=private) % All these properties are immutable.
Code;
end
properties (Dependent, SetAccess=private)
Name;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
methods
function out = eq(a, b) %EQ Basic "type-safe" eq
check_type_safety(a, b);
out = reshape([a.Code],size(a)) == reshape([b.Code],size(b));
end
function [tf,loc] = ismember(a, b)
check_type_safety(a, b);
[tf,loc] = ismember(reshape([a.Code],size(a)), [b.Code]);
end
function check_type_safety(varargin) %CHECK_TYPE_SAFETY Check that all inputs are of this enum type
theClass = class(varargin{1});
for ii = 2:nargin
if ~isa(varargin{ii}, theClass)
error('Non-typesafe comparison of %s vs. %s', theClass, class(varargin{ii}));
end
end
end
% Display stuff:
function display(obj)
disp([inputname(1) ' =']);
disp(obj);
end
function disp(obj)
if isscalar(obj)
fprintf('%s: %s (%d)\n', class(obj), obj.Name, obj.Code);
else
fprintf('%s array: size %s\n', class(obj), mat2str(size(obj)));
end
end
function name=get.Name(obj)
mc=metaclass(obj);
mp=mc.Properties;
for ii=1:length(mp)
if (mp{ii}.Constant && isequal(obj.(mp{ii}.Name).Code,obj.Code))
name = mp{ii}.Name;
return;
end;
end;
error('Unable to find a %s value of %d',class(obj),obj.Code);
end;
end
end
Thanks,
Mason
Toys = {'Buzz', 'Woody', 'Rex', 'Hamm'};
Toys{3}
ans = 'Rex'
If you need the enumerated types just for passing to C# or .NET assembly,
you can construct and pass the enums with MATLAB 2010:
A = NET.addAssembly(MyName.dll)
% suppose you have enum called "MyAlerts" in your assembly
myvar = MyName.MyAlerts.('value_1');
you can also check the official MathWorks answer at
How do I use .NET enumerated values in MATLAB 7.8 (R2009a)?
// the enum "MyAlerts" in c# will look something like this
public enum MyAlerts
{
value_1 = 0,
value_2 = 1,
MyAlerts_Count = 2,
}

Load a record using dot notation and strings from an array in Modelica

Is there a way to load a record in Modelica, and manipulating part of the record directory with a string from an array?
I included the minimal working example below, in summary, I have two different records with parameter values named Cylinder and Board and I have an array containing their names. I would like to access one set of parameter values in a function, depending on the user input "ShapeNumber". So when the user is putting a 1, load the parameters from the Cylinder record, when the user puts a 2, load the parameters from the Board record. Ideally, I would like to add the string "Cylinder" or "Board" into the dot notation for loading the record, as indicated in the code below.
package Test_things
record General_parameters
parameter Real Length "Length in m";
end General_parameters;
record Cylinder_parameters
extends General_parameters;
parameter Real Diameter "Diameter in m";
end Cylinder_parameters;
record Board_parameters
extends General_parameters;
parameter Real Width "Width in m";
parameter Real Depth "Depth in m";
end Board_parameters;
record Parameter_values
constant Test_things.Cylinder_parameters Cylinder(Length=10, Diameter=0.5);
constant Test_things.Board_parameters Board(
Length=20,
Width=1,
Depth=0.01);
constant String[2] ShapesArray = {"Cylinder","Board"};
end Parameter_values;
function Length_tester
input Integer ShapeNumber; //Which shape from within the shape array is tested
output Boolean LongEnough;
Test_things.Parameter_values Values; //Gives Values.Cylinder, Values.Board, Values.ShapesArray
protected
String ShapeName;
Real Length;
algorithm
//Load correct shape
ShapeName := Values.ShapesArray[ShapeNumber];
// This is what I would like: Length := Values.{ShapeName}.Length;
// which results in one of the two lines of code below.
// Length := Values.Cylinder.Length;
// Length := Values.Board.Length;
// This works for now, but has to be adjusted whenever a new shape is used
if ShapeName == "Cylinder" then
Length := Values.Cylinder.Length;
elseif ShapeName == "Board" then
Length := Values.Board.Length;
end if;
if Length > 15 then
LongEnough := true;
else
LongEnough := false;
end if;
end Length_tester;
model Main
Boolean LongEnoughCylinder;
Boolean LongEnoughBoard;
equation
// Test Cylinder
LongEnoughCylinder = Length_tester(1);
// Test Board
LongEnoughBoard = Length_tester(2);
end Main;
end Test_things;
I found the work around with the if-statement, but when I add a new record, I have to update that if-statement in every function I have, rather than only updating the array with the names of the records.
Thank you for any help!
What you try to do is currently not possible, as Modelica does not support dynamic creation of class paths. All class paths must be hard coded.
Therefore your if/else workaround is a legit solution. To keep the maintainability low, you could create a function getLength with contains the if/else logic and all your other functions will use this one.
Below you can find the solution which I would use. Everything is made as generic as possible, so you can use an arbitrary number of shapes of any kind. To do so, there is the generic shape type Shapewith all possible shape parameters. Then there are the specialized shapes Board and Cylinder, which set not needed parameters on 0 in combination with the keyword final, so users can not modify them. This allows to create arrays of shapes, containing the basic shape type, as well as the specialized shapes. The testLength function will then be very simple, accepting an array of shapes. The downside of this solution is (for you as developer), that new shapes with new parameter require an update the basic shape type and the specialized shapes.
package Test_things
record Shape "Generic shape with all possible parameters"
import SI = Modelica.SIunits;
// Common parameters
parameter ShapeTypes shapeType "Kind of shape";
parameter SI.Length length;
// Board parameters
parameter SI.Length width;
parameter SI.Length depth;
// Cylinder parameters
parameter SI.Diameter diameter;
end Shape;
type ShapeTypes = enumeration(Cylinder, Board);
record Cylinder "Cylinder shape with unneeded parameters set on final 0"
extends Shape(final shapeType=ShapeTypes.Cylinder, final width=0, final depth=0);
end Cylinder;
record Board "Board shape with unneeded parameters set on final 0"
extends Shape(final shapeType=ShapeTypes.Board, final diameter=0);
end Board;
function testLength "Check if length of a specific shape in an array of shapes is bigger than 15"
input Integer shapeNumber "Shape of interest";
input Shape shapes[:] "Array of shapes";
output Boolean longEnough;
algorithm
longEnough := shapes[shapeNumber].length > 15;
end testLength;
model Main
constant Shape shapes[:] = {
Board(length=20, width=1, depth=0.01),
Cylinder(length=1, diameter=2)};
// note: this works in OpenModelica only with the prefix constant, parameter does not compile
// in Dymola it works with both
Boolean longEnoughCylinder;
Boolean longEnoughBoard;
equation
// Test Cylinder
longEnoughCylinder = testLength(1, shapes);
// Test Board
longEnoughBoard = testLength(2, shapes);
end Main;
end Test_things6;
Some notes on style:
all classes except of function should be written in upper case
all instances, parameters, etc. should be written in lower case
instead of writing the unit into the comment, use SI units