On Sun, 14 Nov 2010 03:32:18 -0800 Jonathan M Davis <jmdavisp...@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