Last update March 7, 2012

Typedef-Block



Difference (last change) (no other diffs, normal page display)

Deleted: 166,276d165
jam tangan
jam tangan murah
jam tangan kw
hostgator coupon
kata mutiara
Jasa SEO
EZido
RDAnet
pioneer deh-1300mp
asus a53e-xa2
asus tf101-b1
asus tf101-a1
asus n53sv-eh72
asus republic of gamers g74sx
asus acer a5250
acer chromebook ac700
asus asus 53u
lg infinia 55lw5600
Sonicview 360 premier
asus 7 cu ft freezer
asus 30 single wall oven
brother cs6000i sewing machine
brother 1034d serger
brother sewing machines
Yokohama Geolandar H/T-S
crib tent tots in mind
kidco peapod plus
foscam fi8910w
samsung pl120 review
gopro helmet cam
Canon SX130IS
powershot s100
ContourHD 1080p
canon vixia hf r21
digital picture frame
canon ef 50mm f1.4
canon ef 70-300mm review
wide angle lenses
moving comfort sports bra
moving comfort bra
womens argyle sweater
bebe dresses
ViewSonic VX2250WM
Le Pan TC 970
Apple MacBook Air MC965LL
Sennheiser CX 880
plantronics cs540
ultrasonic jewelry cleaner
Sennheiser RS120
bose quietcomfort 15 acoustic noise cancelling headphones
logitech harmony one remote
logitech harmony 900
sony mhc-ec69i
sony mhcec909ip
bose wave music system
sony htss380
logitech squeezebox touch
sony dvp-fx970
onkyo tx-nr509
onkyo tx - nr609
onkyo ht-s3400
energy 5.1 take classic home theater system
polk audio psw505
onkyo ht-s5400
onkyo tx-nr709
belkin pf60
onkyo ht-rc360
denon avr-1912
Yamaha YHT-S400BL
fujitsu scansnap s1500
brother hl-2270dw
epson workforce 545
hp laserjet p2055dn
bushnell 8mp trophy cam
toshiba 32c110u
panasonic viera tc-p60s30
VIZIO E220VA
hauppauge wintv dcr-2650
Acer AM3970-U5022
Acer AspireRevo AR3700-U3002
Dell Inspiron i570
Dell GX620
Gateway FX6860-UR20P
Western Digital My Passport Essential SE 1 TB USB 3.0
Fujitsu ScanSnap S1300
Epson Perfection V300
Fujitsu SCANSNAP S1100
NeatDesk Desktop Scanner and Digital Filing System
Epson WorkForce Pro GT-S50
Kodak P811BK
Epson Perfection V330
Viewsonic VX2453MH
Asus VE228H
ViewSonic VA2431WM
Samsung B2230
HP 2711x
ASUS ML228H
Epson PowerLite Home Cinema 8350
Optoma PK301
Epson EX7210
Epson EX5210
ViewSonic PJD5133
Acer X1161P
FAVI RioHD-LED-2
Epson EX3210
ViewSonic PJD6531w
Trinity 360 Breville 800JEXL
Skil 3320-02
Delta 46-460
Grizzly G0555
Delta 18-900L

Typedef Block

A feature proposal for D -- EricAnderton

A means for extending a scalar type in a struct-like way that can:

  • maintain implicit casting to the underlying type
  • allow for operator overloads on scalar types
  • allow for static inheritance of methods when typedefs are 'inherited'
  • transparently expand the role of scalar types throughout the language

Syntax

The typedef statment is extended to support an optional class-like syntax. Note that the secondary form only allows for scalar types, since both structs, and classes have their own semantics for extension (inheritance etc).

typedef <type> <ident>;
typedef <scalar|enum|array|delegate|function> <ident>{
    <methods>
}

Any method signature is allowed, and any operator overload is possible. Constructor and Destructor syntaxes are allowed. The 'this' pesudo-member is also used throughout the typedef's methods, with the understanding that it is actually a pointer to the underlying type (scalar). Any members declared for the typedef must be static, as any non-static data would really make the type a struct not a scalar. The only valid, non-static member available is "this". The static member "init" is available to all typedefs and the static members "min" and "max" are available to non-array types.

Extending previously extended typedefs will force methods to be overloaded and overridden in a manner identical to class inheritance. Public, private and protected method types will be respected according to those rules.

The resulting type becomes a sort of static-class of methods that is only resolvable at compile time. The programmer must be aware that performing implicit or unsafe casts on such a typedef will result in changing the scalar's behavior to the behavior of the resulting type.

Motivation

The basic premise of extending typedef is to modify the behavior of scalars without having to re-implement a complete behavior type. If one wanted to add an attribute to an scalar type, or slightly modify the behavior of a scalar, all while still having the same behavior as the type it replaces, one would have to do no less than:

  • create a class or struct
  • completely emulate the behavior of the underlying type (arithmetic, casting and conversion)
  • implement the slightly divergent or enhanced behaviors, new attributes, etc
This list is deceptively short. There are over two-dozen operators in the D language, most of which apply to all scalar types. The remaining set apply to arrays. All this effort in scalar-type-emulation results in a large amount of code to be written to effectively emulate 90-99% of what is already provided in the scalar it replaces. The result is nothing less than code bloat and a needless duplication of effort.

Yet all this can be avoided if we can just change the parts we want to change. This is where the typedef block comes in.

Examples

By extending the notion of a typedef to include methods as well as just renaming the type, the language immediately becomes more flexible. Here are some examples.

typedef int SmartInt{
    public SmartInt opPos(){ // change opPos into an absolute-value operator
        if(*this < 0) return(-*this);
        return(*this);
    }
}

SmartInt foo = -6;
writefln("foo is: ",+foo); // outputs "foo is 6"

typedef int ClampedInt{ // value stays within range provided
    static this(){
        min = -100;
        max = 100;
    }
    private int clamp(int value){
        if(value > max) return(max);
        else if(value < min) return(min);
        else return(value);
    }
    public int opAssign(int value){
        *this = clamp(value); 
        return(this);
    }
}

ClampedInt foo = -200;
writefln("foo is: ",foo); // outputs "foo is -100"

typedef real FriendlyReal{
    static this(){
        init = 0; // use zero instead of NaN
    }
    public FriendlyReal opDiv(real value){
        if(value == 0) *this = real.NaN;
        else *this = *this / value;
        return(*this);
    }
}

FriendlyReal foo;
writefln("foo is: ",foo); // outputs "foo is 0"
writefln("foo/0 is: ",foo/0); // outputs "foo is NaN"

typedef void delegate()[] SimpleEvent{
    public void opCall(){
         for(void delegate() del; this){
             del(); // call the entire queue
         }
    }
}

void hello1(){ write("hello1 ");
void hello2(){ write("hello2 ");
SimpleEvent foo;
foo ~= &hello1;
foo ~= &hello2;
foo(); // outputs: "hello1 hello2";

Impact on D

The changes to the language needed to support an extended typedef may not be all that extensive. D already performs implicit casting and overload resolution for typedef and aliased types. Structs already enjoy the kind of compile-time class like method semantics that this would require, so that functionality already exists within the language. Also, the typedef statement has a syntax "hole" as there is no equivalent for the block-style declaration (using "{" and "}" ). This meshes perfectly with the overall context-free approach of D's design, and only serves to make it moreso.

Comments

A few comments on the first read-through:

  • how would name lookup actually work? The proposal is not that clear to me exactly what would happen to figure out what function to call.
  • opAssign? eek - that's a new operator for D and potentially very scary.
  • Is the FriendlyReal? example useful? Can't one set the init property of a standard typedef?
BenHinkle

Another variant

In my opinion typedef-blocks and structs are too similar to exists as different constructs. If we allow struct inheritance by means of just adding base struct members to the front of child struct, and allow struct inheritance from basic types it would solve the problem. Casting child struct to base struct can be allowed, but all struct methods must be treated as non-virtual, so we can keep compitability with C structs.

Examples:

// analog for typedef int MyInt
struct MyInt: int {}

//  ( super is just shortcat for cast(int*)this )
struct SmartInt: int {
    public SmartInt opPos(){ // change opPos into an absolute-value operator
        if(*super < 0) return(-*this);
        return(*this);
    }
}

// static array
//  ( using template syntax )
struct AutoSumIntArray(N): int[N] {
    private int _sum = 0;
    int sum() { return _sum; }
    int opIndexAssign(int val, int idx) {
        _sum -= (*super)[idx];
        (*super)[idx] = val;
        _sum += (*super)[idx];
    }
    int opSliceAssign(...) { ... }
}

// dynamic array
//   must use class syntax becouse of reference semantic
class BoundedIntDynArray: int[] {
    int bound = 100;
    this(int l) {
        if(l > bound) assert(0);
        super(l);
    }
    void length(int l) {
        if(l > bound) assert(0);
        super.length = l;
    }
}


FrontPage | News | TestPage | MessageBoard | Search | Contributors | Folders | Index | Help | Preferences | Edit

Edit text of this page (date of last change: March 7, 2012 20:33 (diff))