class1 as property of class2, class1 property initialization?

I have a class:
classdef class1
properties
prop1 = 1;
end
end
and I can easily access prop1 with:
test = class1
test.prop1
ans = 1
If I then put class1 as a property into another class e.g.:
classdef mainClass
properties
class1
end
end
I would like to access class1 propr 1 through mainClass. So I try the following but get an error:
>> test.class1(1).prop1
Index exceeds the number of array elements. Index must not exceed 0.
Why is prop1 not initialized to the value 1? Thanks

 Réponse acceptée

In your definition of mainClass you created a property with the name class1, not the type class1.
This is what you want:
classdef mainClass
properties
class1 (1,1) class1
end
end
Just be careful using this approach. If class1 is a handle class, then all instances of mainClass will share the same class. In that case, you are better off with this approach:
classdef mainClass
properties
class1
end
methods
function obj = mainClass()
obj.class1 = class1;
end
end
end
You may also want to reconsider having a property name that matches a class name. It works, but it may be confusing.

10 commentaires

Thank you Benjamin. I agree about the class name being the same as the type being confusing. I understand the class1 attribute saying that this property must be of type class1, however I thought the (1,1) was just property validation when assigning values to the property (object). Why does it also initialize the object? Is it because it would violate the validation if it initialized as empty?
Benjamin Kraus
Benjamin Kraus le 2 Nov 2022
Modifié(e) : Benjamin Kraus le 2 Nov 2022
You are correct. The default value can't be an empty vector because of the size validation, so by specifying that the size must be a scalar object of class class1, MATLAB will automatically (attempt to) create a scalar instance of that object as the default value of the property. Unless you also specify a default value, the object will be created by calling the class constructor with no input arguments. Without the (1,1) MATLAB will use a default value of class1.empty().
I was wondering about this, and found your post. This may deserve submission as a new question, but I'll put here for now...
Can you explain the thinking behind this more? I'd like to use property validation to restrict the size and class of a particular property only when the property is set. If no default value is set in the classdef, it means I intend for that that property to be set by someone/something else, and that's where I'd expect validation to occur. It seems counterintuitive to assign a default value based on a validation, when the programmer never specifically coded a default value (since the option exist to do so!).
The current behavior makes my use-case somewhat difficult. Consider the following.
classdef MyClassA
properties
Bobj (1,1) MyClassB %Note I do not define a default value!!!
end
methods
function obj = MyClassA()
end
function output = doStuffWithB(obj,input)
if isempty(obj.Bobj) % this won't work! Is there something similar that will?
error('User must first define Bobj')
else
output = obj.Bobj.myBMethod(input); % In my case, a default Bobj won't work, because it needs its own props to be set before use
end
end
end
end
I'd like to create an object of MyClassA, and leave it to the user to define the Bobj property, subject to the validation rules. In a later method, I implement a check to see if the Bobj has been set before proceeding with calculations. This check won't help, because Matlab will create a default object Bobj, even though I never explicity told it too!
Is there a way to cleanly achieve this? (Yes I know, I could do this with set methods and additional hidden properties, etc. but I was hoping for something simpler).
What does the MyClassB constructor look like and what is its behavior? Off the top of my head, a potentially straightforward way to handle this would be for the 0-input constructor to set the appropriate property or properties of the object to indicate in some way that this is a "placeholder". Or to have a Static method of the class that returns an instance of the class that somehow "knows" that it's a placeholder, like MyClassB.placeholder().
As an example if MyClassB had a property like Length, perhaps a MyClassB instance having Length equal to NaN would indicate a "placeholder" or "uninitialized" object. In that case you could either have a method on the MyClassB class that allows one to ask isplaceholder(MyClassBInstance) or you could tie the decision a little closer to the implementation by asking isnan(MyClassBInstance.Length).
J G
J G le 24 Jan 2024
Modifié(e) : J G le 24 Jan 2024
Thanks @Steven Lord, I think something like what you propose is what I will have to do.
In my case, the MyClassB constructor doesn't require any specific constructor arguments. Rather, MyClassA is intended to interact with a specific instantiation of MyClassB, defined elsewhere by the user. Accordingly, MyClassA has a property intended to store the handle to this specific instance of MyClassB. Given the validation behavior creating an undesired default instantiation of MyClassB, I need a way to distinguish between an object of MyClassB specifically created by the user and the default.
Is there a way for an object's constructer to know if it is being called for a property validation default? If so, a some sort of placeholder flag could be set in the constructor that way....
If your MyClassA class is required to interact with a specific instance of MyClassB, shouldn't its constructor require that the user specifies a MyClassB instance as input?
Is your MyClassA class required to be a scalar? If so perhaps it should be a subclass of the matlab.mixin.Scalar class (in which case I don't believe its constructor would ever get called with the 0-input syntax unless its ConstructOnLoad attribute is set to true, as per this documentation page. If you can't create a non-scalar array of the objects MATLAB shouldn't need to determine with which value it should fill unspecified elements.)
If it's not required to be a scalar, what would you want to happen if someone assigns a MyClassA instance to x(2) where x doesn't exist previously? What would the specific instance of MyClassB be for x(1)?
I'm with @Steven Lord on this: If MyClassA is required to have a specific instance of MyClassB, it seems like the property should be Immutable and set by the constructor. You can remove the validation from the property itself and move the validation into the constructor (perhaps using Function Argument Validation).
  • By removing the validation from the property itself, you eliminate the need to define a default value, and MATLAB won't attempt to populate it with a scalar instance of your class.
  • By making the property Immutable the user won't be able to change the value after the constructor is called, so you don't need the validation on the property itself any more anyway.
  • By making the property Immutable it also follows your stated behavior, which is that MyClassA depends on a specific instance of MyClassB, so it can be set once and never changed.
  • Using Function Argument Validation in the MyClassA constructor allows you to basically reuse the same property validation you have now, but within an arguments block, to guarantee that the user provided value is always valid.
  • By requiring the property to be set in the constructor, you can still rely on the value of the property always being valid (with the possible exception of save/load, which might need to be handled separately), so you don't need to have isempty checks scattered throughout your code.
One benefit of being able to specify that a property is (1,1) is so that your own code (within the class) no longer has to check isempty when interacting with the property. Any code (inside or outside the class) that is interacting with the property can rely on the fact that the value of the property is always scalar. If you allow that to be empty, then it partially negates the value of having the validation in the first place.
An alternative to using (1,1) would be to use mustBeScalarOrEmpty, but that would allow the user to set the property value back to empty once it was set to a scalar value, which is why I think Immutable works well in this case.
PS: Yes, this probably would have been more appropriate as a new question, with a link back to this question.
I had thought of making it required in the constructor. My hesitation was more related trying to maintain a standard object setup experience across different classes used in the application. Additionally having it in the constuctor, means that that object must be instantiated prior to creation of a MyClassB object, something I would rather not impose.
I played around with the matlab.mixin.Scalar idea, but didn't get it to work (I may not have been doing it correctly, and didn't spend a lot of time).
In the end, I found a native validitation function MustBeScalarOrEmpty that does the trick, and achieves most of what I want (i.e. an empty default value, property size and class enforecement, self-documentation). See below:
classdef MyClassA
properties
Bobj (1,:) MyClassB {MustBeScalarOrEmpty} % Still provides decent self documentation
end
methods
function obj = MyClassA()
end
function output = doStuffWithB(obj,input)
if isempty(obj.Bobj) % This now will work, because default will be a 1x0 MyClassB object
error('User must first define Bobj')
else
output = obj.Bobj.myBMethod(input);
end
end
end
end
@Benjamin Kraus, sorry! It seems that I didn't see your post prior to writing my recent comment! As you can see I ended up independently discovering the second solution you proposed using mustBeScalarOrEmpty.
I'll think more about your preffered solution. I do hear the benefits as you so eloquently spelled them out. As I mentioned, my current hesitation relates more to how the user creates objects for the application, and the fact making it a required constructor argument would impose a limitation on the sequence at which different objects must be created...

Connectez-vous pour commenter.

Plus de réponses (0)

Catégories

En savoir plus sur Functions dans Centre d'aide et File Exchange

Produits

Version

R2022a

Community Treasure Hunt

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

Start Hunting!

Translated by