Clear Filters
Clear Filters

Property Type in constructor vs dependent

42 views (last 30 days)
Timo Kuchheuser
Timo Kuchheuser on 22 May 2024 at 6:47
Commented: Timo Kuchheuser on 23 May 2024 at 6:59
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 Comments
Adam
Adam on 22 May 2024 at 9:27
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.
Timo Kuchheuser
Timo Kuchheuser on 22 May 2024 at 12:09
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));

Sign in to comment.

Accepted Answer

Matt J
Matt J on 22 May 2024 at 18:14
Edited: Matt J on 22 May 2024 at 19:23
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 Comment
Timo Kuchheuser
Timo Kuchheuser on 23 May 2024 at 6:59
Thank you very much for your explanation! Removing the uint8 worked.

Sign in to comment.

More Answers (0)

Products


Release

R2024a

Community Treasure Hunt

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

Start Hunting!