struct vs class
spir
denis.spir at gmail.com
Sun Nov 14 04:14:29 PST 2010
On Sun, 14 Nov 2010 03:32:18 -0800
Jonathan M Davis <jmdavisProg at gmx.com> wrote:
> On Sunday 14 November 2010 03:08:49 spir wrote:
> > Hello,
> >
> >
> > There seems to be 2 main differences between structs & classes:
> > 1. structs instances are direct values, implement value semantics; while
> > class instances are referenced (actually "pointed") 2. classes can be
> > subtyped/subclassed in a simple way; structs cannot be really subtyped --
> > but there is the "alias this" hack
>
> The main thing to remember between structs and classes is that classes are
> polymorphic. If you want polymorphism, use a class. If you don't use a struct.
> Now, if you want a type which is _always_ a reference, then you should probably
> choose a class, but it's quite easy to have a struct which is a reference type
> by having its member variables are on the heap and don't get deep copied be a
> postblit constructor. It is more immediately clear, though, that a class is a
> reference type.
>
> You can get more nuanced on the reasons why you should pick a struct or a class,
> but polymorphism is really what it generally comes down to. If you never intend
> to subclass it or have it implement interfaces, then it should probably be a
> struct.
Thank you, Jonathan.
But what about the copy issue. For instance, in a parsing lib, I currently have a "Source" class that is a kind of "cursored" text (think at a text file), so it's only:
class Source {
string text;
uint index;
this (string text, uint index) {
this.text = text;
this.index = index;
}
}
The advantages that match functions return a source that has stepped forward after successful match (hope you see what I mean, it's a common issue in parsing).
Conceptually, it's pure data, meaning it should be a struct. Also, as you point above, it requires no polymorphism. But I made it a class, because:
* It's created only once, so heavier creation on the heap is irrelevant.
* It's passed from match method to match method huge numbers of time (can be millions of times when parsing code). If I had a struct, it would be copied! (Even if the text itself can be prevented from copy by putting it in a plain array, or "pointed", the fields are still copied.)
* Higher-level patterns that delegate matching to sub-patterns directly get updated source (with new index), precisely because the source is referenced.
For instance, the actual match method of the Choice pattern type holds:
// ...
foreach (Pattern pattern ; this.patterns) {
try
return pattern.check(source); // *******
catch (MatchError e) {
// ...
}
}
// ...
}
The marked line works because Source is referenced. Else, I would have to update source.index manually. Similarly, for a Composition pattern type (every sub-pattern must match in sequence):
foreach (Pattern pattern ; patterns) {
result = pattern.check(source);
nodes ~= result.node;
}
The source is automagically updated by each sub-pattern match.
Thus, this a case where semantic (of value) and feature (no polymorphism) rationales seem both to conflict with practical programming reasons.
Denis
-- -- -- -- -- -- --
vit esse estrany ☣
spir.wikidot.com
More information about the Digitalmars-d-learn
mailing list