support for ToString() in IEntity2

Posts   
 
    
mkamoski avatar
mkamoski
User
Posts: 116
Joined: 06-Dec-2005
# Posted on: 07-Apr-2006 19:02:47   

FWIW, there should be support for ToString() in IEntity2.

In fact, there should be support for ToString() just about everywhere as it is pretty typical.

Anyway, it is just a suggestion.

If there is a compelling reason to not have a ToString(), I would be interested in hearing it; but, I am assuming that everything does (or should) boils down to Object, which does have ToString(), so there seems to be no reason to hide it.

(FYI, I do a lot of generic/dynamic/Reflection-type/meta-data type stuff these days and having ToString() is very helpful in the stuff I do, even though it is non-ideal. Sometimes, it is all that I have. So, that's why it came up.)

Just a thought.

What do you think?

Thank you.

--Mark Kamoski

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39798
Joined: 17-Aug-2003
# Posted on: 07-Apr-2006 20:24:44   

People should spend time on features which matter, so if you need tostring() overrides, use a generic include template and generate them into the entities simple_smile . I don't see a reason to override tostring everywhere, as that leads to the problems that you can't override the method plus whats returned is perhaps not what you want it to return.

Frans Bouma | Lead developer LLBLGen Pro
mkamoski avatar
mkamoski
User
Posts: 116
Joined: 06-Dec-2005
# Posted on: 19-Apr-2006 16:52:20   

Otis--

Regarding this...

Otis wrote:

...I don't see a reason to override tostring everywhere, as that leads to the problems...

...I would say that the reason is that do so would allow more functionality. For example, it would allow meta-data applications to get runtime type information, provide special object factories, and so on.

Anyway, I take your point; but, I respectfully submit that this should be added to the list of things to add.

In terms of implementation, simply wrapping the underlying ToString() would be fine, as long as it is exposed. (I am assuming that System.Object is somewhere at the bottom of the object chain for IEntity2 and the rest of the LLBLGen objects.)

My argument for this change is along the lines of the Liskov Substitution Principle (LSP), that states (more or less)...

"In class hierarchies, it should be possible to treat a specialized object as if it were a base class object"

...which is a principle that, I am sure, you have studied.

(I will note that I do have my own problems with the logical extension of LSP in all cases universally. In universal terms, it is often impractical or not possible to implement in the pure sense. This is because LSP is a principle of idealism and not pragmatism. That is, there exists no universal object model. However, on the other hand, I do think that LSP should be applied when possible/simple/direct, and so on.)

Anyway, this is not a criticism, merely a wish list item. I certainly do not assume to "quote the book" to you. However, I do think having ToString() on every (or virtually every) object in the LLBLGen object model would make sense, (of course, whereever the LLBLGen object derives from some base object that does have a ToString()).

IMHO.

What to you think?

Please advise.

Thank you.

--Mark Kamoski

omar avatar
omar
User
Posts: 569
Joined: 15-Oct-2004
# Posted on: 19-Apr-2006 19:46:07   

In JCL1.x, a BL class that inherits an Entity would provide a ToString() method as a concatenated string of the PrimaryKey values of the entity. This proves to be convenient if we take into account that LLBL dictates that each entity MUST have a primary key.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39798
Joined: 17-Aug-2003
# Posted on: 20-Apr-2006 10:45:47   

mkamoski wrote:

Otis--

Regarding this...

Otis wrote:

...I don't see a reason to override tostring everywhere, as that leads to the problems...

...I would say that the reason is that do so would allow more functionality. For example, it would allow meta-data applications to get runtime type information, provide special object factories, and so on.

I don't see how ToString() is the right place for that. ToString() is IMHO meant for having a string presentation which is humanly readable (and meant for humans) of an object. The purpose you're describing is perfect for the custom properties feature build into LLBLGen Pro simple_smile

Anyway, I take your point; but, I respectfully submit that this should be added to the list of things to add.

If you want runtime info about an object, add custom properties to the entity type.

Frans Bouma | Lead developer LLBLGen Pro
mkamoski avatar
mkamoski
User
Posts: 116
Joined: 06-Dec-2005
# Posted on: 20-Apr-2006 13:59:30   

Otis wrote:

...I don't see how ToString() is the right place for that. ToString() is IMHO meant for having a string presentation which is humanly readable (and meant for humans) of an object. The purpose you're describing is perfect for the custom properties feature build into LLBLGen Pro... If you want runtime info about an object, add custom properties to the entity type...

...OK, but what do say to the LSP argument?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39798
Joined: 17-Aug-2003
# Posted on: 20-Apr-2006 14:33:03   

mkamoski wrote:

Otis wrote:

...I don't see how ToString() is the right place for that. ToString() is IMHO meant for having a string presentation which is humanly readable (and meant for humans) of an object. The purpose you're describing is perfect for the custom properties feature build into LLBLGen Pro... If you want runtime info about an object, add custom properties to the entity type...

...OK, but what do say to the LSP argument?

I don't know the Liskov Substitution Principle so I haven't studied it, but either way, I don't see why ToString() should be overriden to be providing all kinds of info for CODE. ToString() shouldn't be used for interpretation by CODE, as that's very impractical.

Frans Bouma | Lead developer LLBLGen Pro
mkamoski avatar
mkamoski
User
Posts: 116
Joined: 06-Dec-2005
# Posted on: 20-Apr-2006 15:46:56   

Otis--

Regarding this...

Otis wrote:

...I don't know the Liskov Substitution Principle so I haven't studied it...

...I see what you are saying.

However, to follow that up kindly and respectfully, I would suggest that you DO know LSP. I should rather say you have co-discovered LSP informally and applied it as you see necessary/practical, which is fine IMHO. That is exactly what I contend most people do; (see my objections to LSP above).

As proof that LSP is applied (to some extent) in LLBLGen is given by the fact, for example, that some LLBLGen objects DO expose/override methods of their ancestors.

Take, for example, the DataAccessAdapter...

InheritanceOne.Dal.Adapter.DatabaseSpecific.DataAccessAdapter >>> SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterBase >>> System.Object

...it is no coincidence that both DataAccessAdapter and System.Object have ToString(), Equals(), and GetType().

My theory is that you did apply LSP, whether or not you explicitly knew it to be LSP.

There are a lot of decent papers on LSP out there. As with all software design theory, some are idealist, purist, pie-in-the-sky, ivory-tower and others are more practical, sane, and useful.

As usual, it is theoretical-science versus applied-science.

And, again as usual, applied-science pays the bills and makes the wheels turn.

(I just want to be clear that I am in the applied-science camp.)

Anyway, I hope you take this all in stride, as I am sure that you will. Please know that the only reason I bring this kind of thing up for discussion is that I know I have a lot to learn from you (and the whole LLBLGen support team). So, that's what I am trying to do.

Thank you, again, for you kind responses and your excellent product.

--Mark Kamoski

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39798
Joined: 17-Aug-2003
# Posted on: 21-Apr-2006 14:55:21   

mkamoski wrote:

Otis--

Regarding this...

Otis wrote:

...I don't know the Liskov Substitution Principle so I haven't studied it...

...I see what you are saying.

However, to follow that up kindly and respectfully, I would suggest that you DO know LSP. I should rather say you have co-discovered LSP informally and applied it as you see necessary/practical, which is fine IMHO. That is exactly what I contend most people do; (see my objections to LSP above).

As proof that LSP is applied (to some extent) in LLBLGen is given by the fact, for example, that some LLBLGen objects DO expose/override methods of their ancestors.

Take, for example, the DataAccessAdapter...

InheritanceOne.Dal.Adapter.DatabaseSpecific.DataAccessAdapter >>> SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterBase >>> System.Object

...it is no coincidence that both DataAccessAdapter and System.Object have ToString(), Equals(), and GetType().

Erm, those are all inherited from Object.

My theory is that you did apply LSP, whether or not you explicitly knew it to be LSP.

I don't follow, overriding a method from a base class is simply polymorphism and OO. simple_smile So Equals is overriden on an entity to make it perform a different Equals operation than the base class 'Object' which simply does an instance compare.

Frans Bouma | Lead developer LLBLGen Pro
mikeg22
User
Posts: 411
Joined: 30-Jun-2005
# Posted on: 21-Apr-2006 20:30:41   

Otis wrote:

mkamoski wrote:

Otis--

Regarding this...

Otis wrote:

...I don't know the Liskov Substitution Principle so I haven't studied it...

...I see what you are saying.

However, to follow that up kindly and respectfully, I would suggest that you DO know LSP. I should rather say you have co-discovered LSP informally and applied it as you see necessary/practical, which is fine IMHO. That is exactly what I contend most people do; (see my objections to LSP above).

As proof that LSP is applied (to some extent) in LLBLGen is given by the fact, for example, that some LLBLGen objects DO expose/override methods of their ancestors.

Take, for example, the DataAccessAdapter...

InheritanceOne.Dal.Adapter.DatabaseSpecific.DataAccessAdapter >>> SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterBase >>> System.Object

...it is no coincidence that both DataAccessAdapter and System.Object have ToString(), Equals(), and GetType().

Erm, those are all inherited from Object.

My theory is that you did apply LSP, whether or not you explicitly knew it to be LSP.

I don't follow, overriding a method from a base class is simply polymorphism and OO. simple_smile So Equals is overriden on an entity to make it perform a different Equals operation than the base class 'Object' which simply does an instance compare.

LSP just says that you should be able to swap out base and child classes in the same context and the program will still be "correct." I think this is different than polymorphism but its still a pretty standard concept in OO as far as I remember simple_smile

simmotech
User
Posts: 1024
Joined: 01-Feb-2006
# Posted on: 25-Apr-2006 15:34:20   

A few comments and suggestions....

Firstly, although the IEntity2 doesn't explicitly have ToString() as a member, it doesn't actually matter - ToString() (and Equals and GetHashCode and GetType) can be used from any interface reference because .NET knows that they will be available on every object.

I've just noticed that EntityBase doesn't override ToString(). For some reason I was under the impression that it returned the Primary Key value of the entity but I must have been dreaming!

What might be helpful in v2 is to implement IFormattable on IEntity(2) and EntityBase(2). The default output would be as now but would allow the IFormattable.ToString() implementation to be overridden using format specifiers. Possible example uses: 1) Return a list of key values ("k" as the format identifier) 2) Debugging ("d" dumps a list of all of the current values) 3) Concatenate different string values as per the format string. I have some code somewhere that allows a format string to specify one or more properties and it combines them to produce a string for ToString to return. So for a Person entity I could write "$FirstName$ $MiddleNames$ $LastName$" or define an "s" format specifier as a sortable display and return "$LastName$, $FirstName$" or define "f" to be a full or formal name and return "$Title$ $FirstName$ $MiddleNames$ $LastName$ $ (Qualifications)$ The single-letter format specifiers could be defined as additional properties directly in the database. (these are just simplistic examples - the code I have allows optional separators and takes care of null and empty values etc so that result looks neat and tidy)

This could be helpful in reports where just specifying a format specifier allows different representations.

This could of course be done by modifying the original template but it would be far easier to just override a method.

Cheers Simon

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39798
Joined: 17-Aug-2003
# Posted on: 25-Apr-2006 16:53:21   

You'll be able to specify which interfaces to implement on which entities in the designer (which are then added to the class definition header), and then add the implementation of those interfaces in a partial class or user code region.

I think that's a better solution.

Frans Bouma | Lead developer LLBLGen Pro
mkamoski avatar
mkamoski
User
Posts: 116
Joined: 06-Dec-2005
# Posted on: 26-Apr-2006 18:30:38   

Otis wrote:

...I don't follow, overriding a method from a base class is simply polymorphism and OO....

Yes, but if, in this case, one does NOT expose a method in a base class and rather shadows/hides that method, then that is not LSP... as in the case of ToString()...

...since ToString() is in the base class, then (by LSP) it should be in the derived class...

--Mark Kamoski

mkamoski avatar
mkamoski
User
Posts: 116
Joined: 06-Dec-2005
# Posted on: 26-Apr-2006 18:36:32   

mikeg22 wrote:

...LSP just says that you should be able to swap out base and child classes in the same context and the program will still be "correct." I think this is different than polymorphism but its still a pretty standard concept in OO as far as I remember...

I think we are in agreement. I think.

However, to clarify, I am basically just pointing out what I said above...

...that is, LSP says one should not shadow/hide a base class method in the derived class... those methods may be overridden but they should not be hidden...

...(incidentally, and as a side note, the LSP also seems to suggest that if one does override a method in a subclass, then that override should not change the semantic meaning of that method, but since the idea of a methods semantic meaning is a bit fuzzy, I will not touch that topic except to say that it should be obvious that we ceratainly mean that, for example, a sub-class should not override AddNumbers(num1, num2) number and in the override actually subtract the numbers instead of add them as the base class does, which is clearly a change in semantic meaning... but, as I said, that's another topic)...

...so, what I am saying is, that if one were to apply the LSP in the case of IEntity2 and all other LLBLGen objects, then those LLBLGen objects would have ToString() in them if some base class in the inheritance chain also has ToString()...

...and so on...

...(caveat-- I have said, way above, that I do recognize/suggest that it is sometimes impractical/silly to apply the LSP blindly and absolutely... however, that being said, I also do think that in more cases than not, applying the LSP is a good idea, which is what I am suggesting happens for to the ToString() method for LLBLGen object...

...anyway, it is just a thought...

Thank you.

--Mark Kamoski

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39798
Joined: 17-Aug-2003
# Posted on: 26-Apr-2006 18:43:06   

Sorry to say it, but I find it still a weird aspect to do. Just because a base class has a virtual method (object.ToString()) doesn't mean that method THUS should be overriden! One should override the method if the behavior of the method has to change, but only then.

That aside, if you want to override ToString(), why not add a simple include template and generate the override in all the classes? To be blunt: I fail to see why it is of anyone's interest to override ToString in every entity, simply because it's context specific (and thus project specific) what's to be returned by that override. One wants the PK values, other people want something else, and in what format...

Also, isn't it so that LSP is only usable if you solely use the base class' methods? So what's the big deal then confused Because where is this NOT the case in the code generated? That's my problem with this thread... I still have the feeling this thread goes about something completely irrelevant: you have a base type T, and it has some abstract / virtual methods which are abstract / virtual because they are intended to be overriden by derived classes to change behavior/ fill in behavior. That's exactly what's done, as that's normal OO procedure. Where multiple-type inheritance was required, interfaces were used.

So I won't spend time on this, sorry. There's already too much time wasted by human kind on theoretical debates about puristic POV's. simple_smile

(as a sidenote: isn't it so that the LSP is always true unless a method is hidden by using 'new' in a subclass?)

Frans Bouma | Lead developer LLBLGen Pro