Property Type in constructor vs dependent

I am using a function handle in a class and there seems to be a difference whether I set it in properties or in dependent properties. In the second case I need to add a cast to my property or else it doesn't work.
There seems to be some type related thing I do not understand.
Thank you for your help!
Function
This is the function and it's execution (in the class D_b is defined as a double):
D_b = 19;
f = @(t)(D_b/2)*(cos(t)+t.*sin(t));
x = f(linspace(0,pi/4,50)');
Works without cast
When I define it in properties and initialize it via the constructor like below, it works:
properties(SetAccess=immutable, GetAccess=public)
% Base circle diameter
D_b double
% Involute function x axis
i_x function_handle
end
function obj = Spur()
%....
obj.D_b = 38; %Example
obj.i_x = @(t)(D_b/2)*(cos(t)+t.*sin(t));
%....
end
Fails without cast
When I try to use dependents it fails unless I cast D_b/2 to a double:
properties (Dependent)
D_b double
i_x function_handle
end
methods
function db = get.D_b(obj)
db = double(obj.D*cosd(obj.phiDegrees)); %CASTING
end
function ix = get.i_x(obj)
ix = @(t)(obj.D_b/2)*(cos(t)+t.*sin(t));
end
end
If I don't cast the following error occures (which is not the case with my first approach):
Error using *
Integers can only be combined with integers of the same class, or scalar doubles.
Error in Spur>@(t)(obj.D_b/2)*(cos(t)+t.*sin(t)) (line 97)
ix = @(t)(obj.D_b/2)*(cos(t)+t.*sin(t));

3 commentaires

It is a little bit complicated to comment on your code as you are speaking about two issues (or more): one is about casting the output of multiplication of two object properties (which I don't see in your class), and the other one is the method Spur, which apparently works, but, does it? I would suggest to go over OOP basics in MATLAB, there is Onramp and video tutorial by Loren Shure available
Note that my OOP knowledge is a bit limited, so I didn't put this into answer section, but if it helps you, someone will move it.
So, you have error related to this method:
function obj = Spur()
%....
obj.D_b = 38; %Example
obj.i_x = @(t)(D_b/2)*(cos(t)+t.*sin(t));
%....
end
What does this do? If you are trying to modify the value of properties of your class, this will not do it, since you haven't supplied the object (instance of class) to the method. This creates a new structure, with fields D_b, and i_x and returns the structure as an output.
If you supplied the object to it, you would probably get an error, because you have set your class properties to be immutable. This means, that properties are set while object is constructed and afterwards, they cannot be changed.
About the casting issue
function db = get.D_b(obj)
db = double(obj.D*cosd(obj.phiDegrees)); %CASTING
end
I see no problems here, however, I don't see these properties mentioned in your class, so I assume this is different class whose information is missing. You can also inspect values of these object properties by adding the lines above the line with issue or debugging, maybe you forgot to initialize their values.
Adam
Adam le 22 Mai 2024
Spur() is the constructor so this kind of property initialisation works fine. If obj hasn't yet been referenced when you assign to a property in the constructor it will create it at that moment.
For the rest, I'm a little confused what the actual problem is, what is working and what isn't, from the example given.
Sorry for being confusing. I will provide both classes below. I wanted to know why in one case my function (i_x) works without casting and in the other case gives me an error when not casting. Where in my code am I loosing the type class information?
Thank you!!!
Works
classdef SpurWorkingWithoutCast
properties(SetAccess=immutable, GetAccess=public)
m double
N uint8 {mustBeInteger, mustBeNonnegative, mustBeGreaterThan(N,1)}
phiDegrees double {mustBeNonnegative}
D double
D_b double
i_x function_handle
end
methods
function obj = SpurWorkingWithoutCast(m,N,phiDegrees)
obj.m = m;
obj.N = N;
obj.phiDegrees = phiDegrees;
obj.D = obj.m*obj.N;
obj.D_b = obj.D*cosd(obj.phiDegrees);
obj.i_x = @(t)(obj.D_b/2)*(cos(t)+t.*sin(t));
end
end
end
Execute
l = linspace(0,pi/4,50)';
sw = SpurWorkingWithoutCast(2,20,20);
x = sw.i_x(l)
Does not work
classdef SpurWorkingOnlyWithCast
properties(SetAccess=immutable, GetAccess=public)
m double
N uint8 {mustBeInteger, mustBeNonnegative, mustBeGreaterThan(N,1)}
phiDegrees double {mustBeNonnegative}
end
properties (Dependent)
D double
D_b double
i_x function_handle
end
methods
function d = get.D(obj)
d = obj.m*obj.N;
end
function db = get.D_b(obj)
%db = double(obj.D*cosd(obj.phiDegrees));
db = obj.D*cosd(obj.phiDegrees);
end
function ix = get.i_x(obj)
ix = @(t)(obj.D_b/2)*(cos(t)+t.*sin(t));
end
end
methods
function obj = SpurWorkingOnlyWithCast(m,N,phiDegrees)
obj.m = m;
obj.N = N;
obj.phiDegrees = phiDegrees;
end
end
end
Execute
l = linspace(0,pi/4,50)';
sf = SpurWorkingOnlyWithCast(2,20,20);
x = sf.i_x(l)
Error using *
Integers can only be combined with integers of the same class, or scalar doubles.
Error in SpurWorkingOnlyWithCast>@(t)(obj.D_b/2)*(cos(t)+t.*sin(t)) (line 26)
ix = @(t)(obj.D_b/2)*(cos(t)+t.*sin(t));

Connectez-vous pour commenter.

 Réponse acceptée

Matt J
Matt J le 22 Mai 2024
Modifié(e) : Matt J le 22 Mai 2024

2 votes

Property type specifiers, such as the double specifier in,
properties (Dependent)
D_b double
end
only perform conversions when a value is assigned to the property, not when values are extracted from it. That is true regardless of whether the property is Dependent or not. However, a consequence of D_b being Dependent in your particular design of SpurWorkingOnlyWithCast is that you never assign and store a value to the D_b property, so the double specifier above isn't really doing anything. Only the get.D_b() method is determining the type of the returned value db.
Note that the property type specifier isn't always irrelevant when dealing with Dependent properties. If you had defined a set.D_b() method in SpurWorkingOnlyWithCast, then the double specifier would cause any assignment of the form obj.D_b=val to pre-convert val to double before passing it to set.D_b().
Ultimately, I think the best solution is to get rid of the casting of N to uint8. There is no reason to have that if you are going to be deriving non-integer quantities from N:
properties(SetAccess=immutable, GetAccess=public)
N {mustBeInteger, mustBeNonnegative, mustBeGreaterThan(N,1)}
...
end

1 commentaire

TK
TK le 23 Mai 2024
Thank you very much for your explanation! Removing the uint8 worked.

Connectez-vous pour commenter.

Plus de réponses (0)

Catégories

Produits

Version

R2024a

Question posée :

TK
le 22 Mai 2024

Commenté :

TK
le 23 Mai 2024

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by