Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Best Practice - Adding Properties Progromatically 2

Status
Not open for further replies.

Scott24x7

Programmer
Jul 12, 2001
2,826
JP
Hi All,
Now and then (more frequently since I discovered HOW to do this), I find that I need a property in an object, but I don't want to modify the base class, because it's specific to one use. I recently discovered the use of the ADDPROPERTY method, but I'm wondering what the best practice for it's use particularly with "visual" controls, because it's not evident in the properties window, or class browser when you look at it. And I thought, that might be misleading or cryptic for "the next developer to come".
What's the "when to use/when not to use" best practice for this specific to VFP? Or is there one? Or what are your suggestions?
Thanks.


Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Do not modify base class.
Subclass it and add the property in the newly created classs.

Borislav Borissov
VFP9 SP2, SQL Server
 
If you follow pure OOP practices, you will never add properties at run time. Instead, you will either:

- Create a subclass to deal with any special cases that require the property; or

- Add the property to the parent class but leave it unused at that level.

I believe that would constitute the best practice (but that's just my opinion; I'm not an expert).

That said, there might well be reasons for adding properties at run time. I've done so when I've wanted to create objects that represent data entities, and I don't know the number of fields at design time. I can also imagine creating objects that can be returned to a caller from a function (to get over the limitation of only being able to return one value from a function) - again, when you don't know the number of values in advance. But I would think those were fairly exceptional cases.

The only other time I have used the AddProperty method is when writing design-time tools, particularly builders that create or modify objects at design time. That's probably the most common use of the method, and perhaps the reason is was added to the language.

By the way, note that the AddProperty method is not the same as the ADDPROPERTY() function, although they both do more-or-less the same thing.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
As the others said, it's best used sparingly.

One place where it's a good idea is with _Screen. Since it's a globally available object I'll often use it to store values instead of public variables.

There's nothing *wrong* with using AddObject() (either the property or the method) when it's appropriate but it hides implementation and is often a sign of an under-designed system.
 
I'm sure you'll all cringe at this, but I found myself using the "ToolTipText" to store values in. Much to my surprise it worked, and the worst "side effect" it creates was if ToolTips are on, and you hover over the control it shows the value (which actually was really handy too). I'm sure this is a bad habits I shouldn't get into but I really didn't want to add a property to my base class (ok, I'm probably using that wrong, The "Base Classes" as I see them are the "Label", "TextBox", "Image", etc. I created my set of "Base Classes" as subclasses of each of these and called them Labelbase, Imagebase, Textboxbase, etc, so I see how my terminology could seem like a bad practice).

I had an inkling that adding properties programmatically was probably not the "best practice". It didn't feel "right" but I thought I'd see what the current thinking is (as I've found what seemed to be "popular" 15 years ago in some cases has now been overturned, or my understanding 15 years ago in some cases was flawed).

This helped quite a lot. I'm trying to create good practices and habits that are in line with current development thinking.

Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
To add: There is not Intellisense for properties undefined at designtime.

And though Dan addressed AddObject() additional to AddProperty(), that's about the same topic, but has a bit more use cases of putting together complex objects at runtime.

Both these methods are visible in my Property window, I think this is not what you're saying, it's not evident what to put in there, typically you don't override the native behaviour at all, you simply call it like you can call methods triggering events like calling Paint() or Refresh(), it just "triggers" adding a property, something more physical than a behaviour. What might be done with user added code in these methods: You might want to test for already existing names to avoid namespace collisions, you might log added properties or objects. NODEFAULT here would stop the adding of properties or objects, which might be used to deny permissions.

Anyway, the ADDPROPERTY() function is especially useful for the empty class - oNothing = Createobject("Empty") - since a) it has no PEMs, also not AddProperty() method and b) you can't create subclasses of empty, neither visual nor with DEFINE CLASS... as empty. It's most probably designed together with the NAME option of SCATTER/GATHER and INSERT-SQL from object, and extremely useful to create 1:1 record objects and also add further properties to them. A very simple way to pass on one record via parameter.

Bye, Olaf.

 
I'm sure you'll all cringe at this, but I found myself using the "ToolTipText" to store values in.

You're absolutely right. I did cringe.

That's partly because, if you want a way of inspecting properties at run-time, the debugger is the tool of choice. And partly because you might actually want to use ToolTipText for its intended purpose: displaying tool tips.

But, if it works for you, that's fine. I won't try to dissuade you.

By the way, do you know about the Tag property? It's a useful place for storing ad hoc values for the short term. I've never used it myself, but it might be something you would want to consider.

Mike



__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Hi Mike,
I don't intend to make a habit of it. It was kind of cool though, and yeah, I use the debug window for watching values, it really wasn't my intention to be able to see it there as a "tool tip". This was on a command button, and I really didn't want to add a property to the sub-class for use one time... though it did start me thinking to just create (good word) an 'ad-hoc' property to every control, so I don't have to go adding some property to store a variable in for use in the control, particularly for "peculiar" use cases. The TAG property idea is intriguing though, I don't know about this property, which is why I jammed it in ToolTIps, because I at least knew what that would do, (in terms of not really firing an event sequence that I cared about). But won't use it again.

Olaf,
Your point is very interesting, though I don't quite follow/understand the creation of an "Empty Object" that you can't add anything to...?
It's a concept I'm not familiar with.

Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Regarding the Empty object ....

"Empty" is in fact a base class. As its name suggests, by default, it has no properties or methods. But you can add properties programatically, using the AddProperty method.

Why would you use it?

- To create certain data objects, such as a Customer object or an Invoice object. You start with an empty object, and then add properties to represent the various attributes of the customer or whatever.

- With Scatter/Gather. Using the NAME clause, you can scatter into an object. The object in question is an empty object, but after the scatter, it will have acquired properties to match the fields you are scattering.

- For passing parameters to a function, or returning a result from a function. When passing parameters, the object would have a property to correspond to each value you want to pass. This might be neater than passing the parameters individually, and would also be useful if the number of parameters exceeds the maximum of 26. When returning values, it would allow you to return multiple values, which isn't normally supported.

The advantage of using the Empty class in these cases is that it is much "lighter" than the other native classes, and can therefore be instantiated and destroyed faster.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
You can, via the AddProperty function. It's the lightest weight object to only store some properties as it has 0 to start with. The empty class, SCATTER NAME, INSERT FROM NAME and ADDPROPERTY() function all were introduced together in VFP9.

Bye, Olaf.
 
That sounds really interesting, and maybe a little "advanced". Can you give me some kind of example? You've talked in the "conceptual" which was what I asked for, but I'm nos struggling to come up with a practical usage of it, as useful as it does sound...

Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
I already talked about this:

Code:
SCATTER NAME oRecord
ADDPROPERTY(oRecord,"ScatteredAt",DATETIME())
ADDPROPERTY(oRecord,"ScatteredBy",ID())

You can define any object you want with ADDPROPERTY, also if not creating it with SCATTER but empty. One object for N values and nothing more or less. Theses are objects without any code or events, so what are the? vehicles for data or messages or status, things you may want to pass on in one parameter.

Bye, Olaf.
 
Hi Scott,
here are more features of the .AddProperty( ) method, if used programmatically.

You cannot create properties with visibility other than public (e.g. protected or hidden), despite the available third parameter. Example:

Code:
.AddProperty( "MyProperty", "MyData", 2 )    &&   2 - Protected

will trigger a "Feature is only available if the object is in design mode." error.
But you can set the help string with its fourth parameter even for properties already defined, or for read/write native ones, with no error:

Code:
.AddProperty( "MyProperty", "MyNewData", 1, "Something about my property." )
.AddProperty( "Comment", "MyNewComment", 1, "This replaces the obvious 'Stores information about an object.' help string." )

Why you may need to set a help string for a property is another matter. That is a piece of information that comes out with a call to AMEMBERS( ), and I could not find any other way to set it or retrieve it. I still find it somehow useful, because when I "dump" a list of an object's properties, events and methods for debugging purposes (yes, there's a help string for all of them!), it helps me remind what they are all about.

.AddProperty( ) will also raise the _ASSIGN( ) event for the property, and set 0-Changed to the flags you can retrieve with the PEMSTATUS( ) function, even if the value is the same. And even if a native property is read-only. Example:

Code:
.AddProperty( "DataSessionId", .DataSessionId, 1, "Specifies whether the object blah blah blah..." )

So, there may be reasons why it is preferable to create a property at design-time (following the DEFINE CLASS clause) or rather at run-time (in one of its methods). Don't forget that with REMOVEPROPERTY( ) you can only remove properties created at run-time, and that there is no .RemoveProperty( ) method.

Regards,
Dario
 
You've made some good points, Dario.

On the point of only being able to make the property public, the Help specifically says that the third parameter is only available at design time. If you think about it, this makes sense. At run time, the object has not got any descendents, so it makes no difference what the visibility of the new property is.

Interestingly, the ADDPROPERTY() function has no parameter for visibility. The new property is always public, pure and simple.

Similarly with the fourth parameter (what you call the help text). If you are creating the property in the development envrionment (for example, in a builder), you will want that text to show up in the properties window. But that doesn't apply at run time. Again, this parameter is not available in the ADDPROPERTY() function.

Mike





__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
That's true, Mike, the Help does state the third parameter is not applicable at run-time (I forgot to mention), but then, should one even understand why it is so (which is always an option!), what is the reason to have that third parameter in the first place if it has to be 1-Public all the times? And I wonder, too, why that obscure description/help string fourth parameter is meant to be used only in visual design when it still works at run-time (I have not tried it in an executable, though). This sort of things makes me curious...
 
I guess I've just not run into a case where I need to return a group of data (that's not part of an array already). I'll try to keep this in my head though, as knowing of the solution will make me think differently in future challenges, and since my application is like 1/10th done at the moment, I'm sure there will be plenty of challenges to come..
This has all be really helpful.


Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
vfp4ever, it's not easy to understand code running at designtime. code always runs at runtime, doesn't it?

Well, but what is meant is the state of the object you work on. You can instanciate a class via Createobject(), which runs it, but you can also MODIFY a class which loads an object reference to the design time class you can get via ASELOBJ(). Also see the topic of designers or builders. They also have code doing things on classes loaded for working on the definition of them. Some other methods in that area are WriteMethod() and ReadMethod(), for writing and reading code of a visual class object, you can't do that on an instanciated class at runtime, but you can do code creating a vcx class and writing code in it and then use it, so you could even create a VFP IDE in VFP.

Bye, Olaf.
 
Rather than talking about code running at design time, it would be more accurate to talk about code running in the development environment. That would cover builders and other development tools that generate or modify code.

As I mentioned earlier, it's likely that the AddProperty method was introduced to the language with exactly those development environment tools in mind.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Yes, that'd make it clearer, still it's not covering it, you can run any code in the IDE and still not be able to use WriteMethod on any object, just the ones specially initiated in design mode. You can't do oForm = CreateObject("form") and oForm.WriteMethod("click","? 'click'") in the command window. If you do you get error "Feature is only available if the object is in design mode.", so "code running in the development environment" does not hit the head either.

Bye, Olaf.

PS: You can see a valid use of WriteMethod in faq184-6512, where it writes CLEAR EVENTS into the unload event of a form, which is in the design mode at that time and the reference is taken from ASELOBJ. It's the main ingredient the form is not running, but in design mode.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top