On Sun, 14 Nov 2010 03:32:18 -0800
Jonathan M Davis <[email protected]> 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