Thread overview
Compile-time exceptions
Nov 24, 2008
bearophile
Nov 24, 2008
Denis Koroskin
Nov 24, 2008
Christopher Wright
Nov 24, 2008
bearophile
Nov 25, 2008
bearophile
Nov 25, 2008
Christopher Wright
Nov 25, 2008
bearophile
Nov 25, 2008
Denis Koroskin
Nov 25, 2008
bearophile
Nov 26, 2008
Christopher Wright
November 24, 2008
This is a generic example of a small function template (it's similar to a function with the same name in Mathematica. It that returns the result of the callable 'func' applied n times to 'item'):


TyItem nest(TyFun, TyItem)(TyFun func, TyItem item, int n) {
    static assert(IsCallable!(TyFun), "nest(): func must be a callable");
    static assert(CastableTypes!(ReturnType!(TyFun), TyItem),
                  "nest(): func must return a type castable to item.");
    if (n < 0)
        throw new ArgumentException("nestList(): n must be >= 0");

    for (int i = 1; i <= n; i++)
        item = func(item);
    return item;
} // End of nest()


Its unit tests contain the following stuff too, because raising that exception is part of the user interface of that function:

unittest {
    ...
    assert(Throws!(ArgumentException)(nest(&sin, 0.1, -1)));
    ...
    //nest("hello", 0.1, -1); // static asserts
    ...
}

(I'm waiting to have a better Throws!() in the std lib that doesn't require to be put into an assert()).
But at the moment I haven't found ways to unit test the first two static asserts, so I just put tests in the unittest for them, and I comment them out to make the unittest run.

That problem may be solved with a "static try" and "static catch", that work at compile time :-) (I think this isn't related with the Java static exceptions).

static try
    deleg();
static catch (StaticAssert a) {
    ...
}

Bye,
bearophile
November 24, 2008
On Mon, 24 Nov 2008 13:15:36 +0300, bearophile <bearophileHUGS@lycos.com> wrote:

> This is a generic example of a small function template (it's similar to a function with the same name in Mathematica. It that returns the result of the callable 'func' applied n times to 'item'):
>
>
> TyItem nest(TyFun, TyItem)(TyFun func, TyItem item, int n) {
>     static assert(IsCallable!(TyFun), "nest(): func must be a callable");
>     static assert(CastableTypes!(ReturnType!(TyFun), TyItem),
>                   "nest(): func must return a type castable to item.");
>     if (n < 0)
>         throw new ArgumentException("nestList(): n must be >= 0");
>
>     for (int i = 1; i <= n; i++)
>         item = func(item);
>     return item;
> } // End of nest()
>
>
> Its unit tests contain the following stuff too, because raising that exception is part of the user interface of that function:
>
> unittest {
>     ...
>     assert(Throws!(ArgumentException)(nest(&sin, 0.1, -1)));
>     ...
>     //nest("hello", 0.1, -1); // static asserts
>     ...
> }
>
> (I'm waiting to have a better Throws!() in the std lib that doesn't require to be put into an assert()).
> But at the moment I haven't found ways to unit test the first two static asserts, so I just put tests in the unittest for them, and I comment them out to make the unittest run.
>
> That problem may be solved with a "static try" and "static catch", that work at compile time :-)
> (I think this isn't related with the Java static exceptions).
>
> static try
>     deleg();
> static catch (StaticAssert a) {
>     ...
> }
>
> Bye,
> bearophile

This has already been discussed:
http://digitalmars.com/d/archives/digitalmars/D/static_try_catch_construct_would_be_helpful_66794.html
November 24, 2008
bearophile wrote:
> But at the moment I haven't found ways to unit test the first two static asserts, so I just put tests in the unittest for them, and I comment them out to make the unittest run.

assert (!is (typeof (nest(1, 1, 1)))); // int is not callable

If you're using d2:
assert (!__traits (compiles, nest(1, 1, 1)));
November 24, 2008
Christopher Wright:
> assert (!is (typeof (nest(1, 1, 1)))); // int is not callable

Oh, right, that syntax isn't much elegant, but it seems to work, and it's doable. Thank you. I'll probably use it now and then.

You can use it statically too :-)
static assert (!is (typeof (nest(1, 2, 3)))); // int is not callable


>If you're using d2:<

Not yet.

Bye,
bearophile
November 25, 2008
Christopher Wright Wrote:
> assert (!is (typeof (nest(1, 1, 1)))); // int is not callable

I have just used a static assert version of that in about one hundred places in my dlibs, with good results, thank you :-) It has replaced lot of commented out and mostly useless lines of code with actual code that can spot problems at compile time. This begs for compiler (or standard lib) support, I think.

On the topic of idioms: I may also use an idiom just shown to me by downs, to allow "passing" "function templates" to other functions:
_sum { T opCall(T)(T[] array) { ... } } _sum sum;
That's another situation where I think some built-in syntactic sugar can be useful. Do you have ideas regarding a possible syntax/statement?

Bye,
bearophile
November 25, 2008
bearophile wrote:
> On the topic of idioms: I may also use an idiom just shown to me by downs, to allow "passing" "function templates" to other functions:
> _sum { T opCall(T)(T[] array) { ... } } _sum sum;

I don't know what this is doing. That code fragment won't compile, and it isn't showing usage.

Passing an instantiation of a function template is easy -- you just pass in a function. Passing a template requires an alias template parameter, I think.

Virtual templates would allow you to use polymorphism in this case, but that's not going to be considered for quite some time, if at all.

> That's another situation where I think some built-in syntactic sugar can be useful. Do you have ideas regarding a possible syntax/statement?
> 
> Bye,
> bearophile
November 25, 2008
Christopher Wright Wrote:
> I don't know what this is doing. That code fragment won't compile, and it isn't showing usage.

Sorry:

struct _add { T opCall(T.init + T.init)(T x) { return x+x; } }
_add add;

Now you can give it to a function, without the need of specializing it for a type T first (you can't give the pointer to a template). (This may also be faster, because there isn't a delegate to call).
(Haskell is statically typed and allows you do more complex things with a clean enough syntax).


> Virtual templates would allow you to use polymorphism in this case, but that's not going to be considered for quite some time, if at all.

Can you explain?

Bye,
bearophile
November 25, 2008
On Tue, 25 Nov 2008 15:28:53 +0300, bearophile <bearophile@lycos.com> wrote:

> Christopher Wright Wrote:
>> I don't know what this is doing. That code fragment won't compile, and
>> it isn't showing usage.
>
> Sorry:
>
> struct _add { T opCall(T.init + T.init)(T x) { return x+x; } }
> _add add;
>

Did you mean:

struct _add { typeof(A.init+B.init) opCall(A, B)(A a, B b) { return a + b; } }
_add add;

auto x = add(3, 0.1415926); ?

> Now you can give it to a function, without the need of specializing it for a type T first (you can't give the pointer to a template). (This may also be faster, because there isn't a delegate to call).
> (Haskell is statically typed and allows you do more complex things with a clean enough syntax).
>

Yes, it is a nice trick.
November 25, 2008
Denis Koroskin:
> Did you mean:

Yes, of course :-)

Bye,
bearophile
November 26, 2008
bearophile wrote:
> Christopher Wright Wrote:
>> I don't know what this is doing. That code fragment won't compile, and it isn't showing usage.
> 
> Sorry:
> 
> struct _add { T opCall(T.init + T.init)(T x) { return x+x; } }
> _add add;
> 
> Now you can give it to a function, without the need of specializing it for a type T first (you can't give the pointer to a template). (This may also be faster, because there isn't a delegate to call).
> (Haskell is statically typed and allows you do more complex things with a clean enough syntax).

I thought you could do this with an alias parameter, but perhaps I'm wrong. It's not the sort of thing I try to do, usually.

>> Virtual templates would allow you to use polymorphism in this case, but that's not going to be considered for quite some time, if at all.
> 
> Can you explain?

Like generics in C#. Java's just hiding casts with its generics, but C# does specialized code generation at runtime for each generic type it creates. D could do this with full templates, not just generics, and at compile time, but it'd require an extra compilation step before linking, most likely.

> Bye,
> bearophile