subclassing
spir
denis.spir at gmail.com
Tue Nov 2 07:04:52 PDT 2010
Hello,
After the exchanges on ranges, I am experimenting around this notion as a way to learn about D classes, subclassing, generics, etc...
In the code below, there are three obscure points for me:
* I wrote Range as class, but I rather meant an interface. D does not let me do that, apparently because there is no data slot in a D interface. Is then an interface a kind of data-less superclass? Or is there something I misunderstand?
* Why does D allow me redefining (data) slots in the subclass OddSquares, which exist in the superclass? (I did this first without noting, by copy & paste ;-)
* There is a bug in function find -- see DEBUG lines in this func and in main. For any reason, the passed range loses its data (.element==0). If I change find's interface to take a range of type OddSquares, then all runs fine. I don't know what more to do to find the bug...
(I hope you don't mind spaces before ';', I like to put purely syntactic thingies aside from proper code.)
Thank you for your help,
Denis
PS: I like very much this interface for input ranges :-) Decided to make output data plain state (slots T element & bool continues); only step() is a method. I know this is not true OO for some conception of OO, but it is ok for me. I also like in this design the fact that the constructor sets the range's initial state -- or is supposed to -- so that we can use the range at once, without calling step() once to initialise it.
Iteration using for as shown below is indeed equivalent to:
auto range = ...;
while (range.continues) {
doSomethingWith(range.element);
range.step();
}
which is analog to traditional list traversal using
while (node.next) {
doSomethingWith(node.element);
node = node.next;
}
except the range interface can be applied to any kind of collection, taken globally or partially, even virtual like in the example of OddSquares below.
=================== code ======================
/+ experimentation on notion of range
+/
import std.stdio ; // write*
import std.string ; // join , format
import std.conv ; // to!(destType)(expression)
class Range(T) {
alias T type ; // meta info
// external state
T element ;
bool continues ;
// methods
abstract void step() ;
}
class OddSquares(T) : Range!T {
alias T type ; // meta info
// external state
T element ;
bool continues ;
// internal state
private T number ;
private T max ;
// methods
override void step() {
if (this.number > this.max) {
// continues range...
this.continues = false ;
} else {
// ... or step once
this.continues = true ;
this.element = this.number * this.number ;
this.number += 2 ;
}
}
this(T min, T max) {
// set initial internal state
if (min%2 == 1)
this.number = min ;
else
this.number = min+1 ;
this.max = max ;
// set initial external state
this.step() ;
}
}
T find (T) (OddSquares!T range , bool function(T element) predicate) {
T element ;
writeln("***", range.element) ; // DEBUG
for (; range.continues ; range.step) {
element = range.element ;
writeln(element) ;
if (predicate(element))
return element ;
}
return 0 ; // placeholder, should be throw Exception
}
void main() {
OddSquares!int range ;
int element ;
// traversal
range = new OddSquares!int(1,9) ;
writef ("elements of type %s: ", typeid(range.type)) ;
for (; range.continues ; range.step) {
element = range.element ;
writef("%s ", element) ;
}
writeln() ;
// find
range = new OddSquares!int(10,20) ;
writeln("***", range.element) ; // DEBUG
element = find!int(range, function bool(int e){return (e>200 && e<250);}) ;
writeln("found element: ", element) ;
}
================== output =====================
=== buggy
elements of type int: 1 9 25 49 81
***121
***0
found element: 0
=== correct
elements of type int: 1 9 25 49 81
***121
***121
found element: 225
-- -- -- -- -- -- --
vit esse estrany ☣
spir.wikidot.com
More information about the Digitalmars-d-learn
mailing list