Developer forums (C::B DEVELOPMENT STRICTLY!) > CodeCompletion redesign
Refectoring of the Token class
blauzahn:
I agree with oBFusCATed.
a general advice: Inheritance should be used only, if you really need polymorphic use -- that is:
runtime dispatch via virtual functions. This helps to avoid having "if" or "switch"
at all places you use the things, which is error prone and fragile, especially in maintenance.
I usually try to reduce the the base class to have one single responsability: Providing
a pure interface that expresses a concept of polymorphic use. That means:
neither any implementation nor any data-member. Think of "design
by contract". All implementors have to follow the Liskov-Substitution principle as soon as
the instance is created. Usually, you have a factory method, that is the only place which
knows the distinction and decides, what instance to create properly and give back to the caller.
In the proposed design, the caller still has to know all the types and therefore
still forces you to use "if" or "switch" and casts, which is unfortunate.
The fact, that the subclasses have a ctor which all take the same arguments is another hint,
that they stand for a missing concept (class) which wants to be born. Perhaps
the subclasses should HAVE one data-member of this kind instead of BEING them in form
of several data-members in the base class.
Or is it even better to split the class into a) token and b) TreeItem
because these seem to be separate ideas and can help to separate things that
may have to remain mutable from things that can become const.
Do you know this stuff?
* Talks, given by Bjarne Stroustrup and Sean Parent at Going Native Conference GN2013,
see also the Panel Videos
* book by Kent Beck: "Implementation Patterns"
* books by Robert C. Martin: "Clean Code", "Agile Software Development"
* podcast on hanselminutes.com: Robert C. Martin: SOLID-principle
* book by Michael Feathers: "Working Effectively with Legacy Code"
Alpha:
My plan with the cc_interface branch is to try to stabilize all current implemented features, and port over the Fortran plugin. Then try for a merge. (I am realizing that if I wait until everything I wanted to add is complete, this branch will be a very long time in coming.)
(Changing the structure of the Token class will require modifications in the implementation of CC's interface functions, but CCManager should not require any changes.)
ollydbg:
--- Quote from: blauzahn on November 28, 2013, 03:59:24 pm ---I agree with oBFusCATed.
a general advice: Inheritance should be used only, if you really need polymorphic use -- that is:
runtime dispatch via virtual functions. This helps to avoid having "if" or "switch"
at all places you use the things, which is error prone and fragile, especially in maintenance.
--- End quote ---
Thanks for the comments.
--- Quote ---I usually try to reduce the the base class to have one single responsability: Providing
a pure interface that expresses a concept of polymorphic use. That means:
neither any implementation nor any data-member. Think of "design
by contract". All implementors have to follow the Liskov-Substitution principle as soon as
the instance is created. Usually, you have a factory method, that is the only place which
knows the distinction and decides, what instance to create properly and give back to the caller.
In the proposed design, the caller still has to know all the types and therefore
still forces you to use "if" or "switch" and casts, which is unfortunate.
--- End quote ---
OK, Thanks. I still have a question. For example, I have a Token (base class), and some derived class, like ScopeToken, ClassToken, FunctionToken, ClassTemplateToken..... Note: Here the name "Token" just means "Symbol" in the sense of "symbol table".
Some class has its special member functions, like: FunctionToken and FunctionTemplateToken class may have some functions to handle arguments, so do we need to collect all the interface to the abstract base class? I mean the base class may have a pure virtual function named XXXArguments()? I need to store all the Token* pointers in the TokenTree(yes, it is the symbol table), If I want to avoid the use of "if" or "switch", the only way I can do is to extract all the functions in the base class?
--- Quote ---The fact, that the subclasses have a ctor which all take the same arguments is another hint,
that they stand for a missing concept (class) which wants to be born. Perhaps
the subclasses should HAVE one data-member of this kind instead of BEING them in form
of several data-members in the base class.
Or is it even better to split the class into a) token and b) TreeItem
because these seem to be separate ideas and can help to separate things that
may have to remain mutable from things that can become const.
--- End quote ---
Sorry, I don't understand much well, can you give more details? Thanks.
--- Quote ---Do you know this stuff?
* Talks, given by Bjarne Stroustrup and Sean Parent at Going Native Conference GN2013,
see also the Panel Videos
* book by Kent Beck: "Implementation Patterns"
* books by Robert C. Martin: "Clean Code", "Agile Software Development"
* podcast on hanselminutes.com: Robert C. Martin: SOLID-principle
* book by Michael Feathers: "Working Effectively with Legacy Code"
--- End quote ---
I just watch the lecture by Bjarne Stroustrup, very nice. But I found that most books are using Java as examples in the book, not C++. :(
oBFusCATed:
--- Quote from: ollydbg on December 01, 2013, 04:10:22 pm ---If I want to avoid the use of "if" or "switch", the only way I can do is to extract all the functions in the base class?
--- End quote ---
But then you'll end with a class that looks like the current Token class.
The new token class must have only common stuff in it.
The idea is to minimize the usage of switches, but most of the time you can't remove them all.
One option is to use http://en.wikipedia.org/wiki/Visitor_pattern but I always fill guilty when I use it.
Another option is to find all switch statements and then define a single method in the base class for each switch...
blauzahn:
--- Quote ---But then you'll end with a class that looks like the current Token class.
--- End quote ---
Yes. And if it works now, there is no need to hurry for a change. Let the ideas ripen.
--- Quote ---the base class may have a pure virtual function named XXXArguments()?
--- End quote ---
No. The methods should get the necessary things inseparable from the call. Just ordinary arguments.
That makes it easy to understand and to use it right and harder to do it wrong. And it minimizes
state and side effects.
--- Quote ---I need to store all the Token* pointers in the TokenTree
--- End quote ---
...but be aware of who owns them, who deletes them, even in case of exceptions. That's why
alternatives to raw pointers may be an option (see GN2013 Sean Parent). No leaks! No
dangling pointer!
--- Quote ---Sorry, I don't understand much well, can you give more details?
--- End quote ---
e.g. separate the functionality/data in the existing Token Class that does not have to be coupled.
(strive for loose coupling, high cohesion, single responsabilty etc.)
a) class TokenLocation{ wxString name, unsigned int file, unsigned int line, size_t ticket };
b) class TokenTreeItem{
bool AddChild(int childIdx);
bool DeleteAllChildren();
bool HasChildren() const;
}
class Token
{
...
TokenLocation m_Location; // naming needs improvement
TokenTreeItem m_TreeItem;
};
If the interface remains the same, all changes are simply implementation details. The code
could be improved by applying small refactoring steps without affecting client code.
--- Quote ---But I found that most books are using Java as examples in the book, not C++.
--- End quote ---
Yes. And with C++ you are not limited to "true OO-Style". Nevertheless, you could
learn a lot of language independant things from the text. The code-samples are
general enough and easy to understand for a C++-programmer. Just do not to transfer
everything blindly to C++. E.g: in C++, the default is value semantics whereas in
Java and C#, it is reference semantics. That makes quite a difference. Exploit this in
your design (using constness, immutability, minimized state, especially shared one etc).
Navigation
[0] Message Index
[*] Previous page
Go to full version