View mode: basic / threaded / horizontal-split · Log in · Help
June 17, 2012
Re: Proposal to add 'Elements of Programming' Concepts to std.traits
On Sunday, June 17, 2012 08:38:41 Philippe Sigaud wrote:
> On Sat, Jun 16, 2012 at 9:22 PM, bearophile <bearophileHUGS@lycos.com> 
wrote:
> > I see. is that semantically different from this (beside being shorter)?
> > 
> > struct NoZero {
> >    int value;
> >    this(int x) { value = x; }
> >    alias value this;
> >    invariant() { assert(value != 0); }
> > }
> > void main() {
> >    auto a = NoZero(5);
> >    auto b = NoZero(0);
> > }
> 
> The invariant isn't invoked through alias this, it seems:
> 
> void main() {
>    auto a = NoZero(5);
>    a = 0; // compiles and runs happily
> }

It wouldn't be. No public function was called. All you did was access the 
public member variable. Having public members and invariants at the same time 
doesn't work very well.

- Jonathan M Davis
June 17, 2012
Re: Proposal to add 'Elements of Programming' Concepts to std.traits
On Sun, Jun 17, 2012 at 8:42 AM, Jonathan M Davis <jmdavisProg@gmx.com> wrote:

> It wouldn't be. No public function was called. All you did was access the
> public member variable. Having public members and invariants at the same time
> doesn't work very well.

If I change

int value;

to

private int value;

it can still be accessed through alias this (I guess) and no invariant
is called.
June 17, 2012
Re: Proposal to add 'Elements of Programming' Concepts to std.traits
On Sunday, June 17, 2012 09:04:16 Philippe Sigaud wrote:
> On Sun, Jun 17, 2012 at 8:42 AM, Jonathan M Davis <jmdavisProg@gmx.com> 
wrote:
> > It wouldn't be. No public function was called. All you did was access the
> > public member variable. Having public members and invariants at the same
> > time doesn't work very well.
> 
> If I change
> 
> int value;
> 
> to
> 
> private int value;
> 
> it can still be accessed through alias this (I guess) and no invariant
> is called.

Well, I'm not sure if it's supposed to be legal to access value like that if 
it's private, but public or private has nothing to do with the invariant in 
this  case. The invariant only runs when you call public _functions_ (it may 
be run with package and protected as well - I don't recall - but never with 
private). It's run before and after they're executed. You're accessing a 
member _variable_. That's why the invariant isn't run. It doesn't matter what 
the access level of a variable is, the invariant is never run just because you 
accessed it. That's why if you want to be able to guarantee your invariants, 
you should never have public member variables on types with an invariant. And 
if alias this allows you to expose a private member variable, then it's in the 
same boat as a public one. Invariants and public member variables just don't 
mix.

- Jonathan M Davis
June 17, 2012
Re: Proposal to add 'Elements of Programming' Concepts to std.traits
That's a *lot* more code but I think we could do something like

struct NoZero {
   private int _value;

   invariant() { assert(_value != 0); }

   this(int x) { _value = x; }

   NoZero opBinary(string op)(const ref NoZero rhs) {
   	return NoZero(mixin("this._value"~op~"rhs._value"));
   }
   NoZero opBinary(string op)(int rhs) {
   	return NoZero(mixin("this._value"~op~"rhs"));
   }
   ref NoZero opUnary(string op)() if(op=="++"||op=="--"){
   	mixin(op~"this._value;");
   	return this;
   }
   ref NoZero opAssign(int rhs) {
   	value = rhs;
   	return this;
   }

   @property int value() const  { return _value; }
   @property void value(int newValue) { _value = newValue; }

   alias this value;
}

void main(){
   NoZero a = 1;
   auto b = a; // copyable
   // --b; would assert
   auto c = b+1;
   auto d = c+a;
}

Note the implementation is incomplete, still need to implement
comparison to bool, operator'!' , unary '+', '-', '~', checks for
overflows. It's a bit of work but I think it can be done.
June 17, 2012
Re: Proposal to add 'Elements of Programming' Concepts to std.traits
On Sun, Jun 17, 2012 at 10:20 AM, Guillaume Chatelet
<chatelet.guillaume@gmail.com> wrote:

Nice.

You can also add:

  this(NoZero nz) { _value = nz._value; }

and

  ref NoZero opAssign(NoZero rhs) {
      value = rhs._value;
      return this;
  }

this allows code like this:

a = a-a; // asserts
a = a*0; // asserts

An obvious generalization is to template the struct on a predicate:

struct Constrained(T, alias pred) {
  private T _value;

  invariant() { assert(pred(_value)); }

  this(T x) { _value = x; }
  this(Constrained c) { _value = c._value; }

  Constrained opBinary(string op)(const ref Constrained rhs) {
      return Constrained(mixin("this._value"~op~"rhs._value"));
  }
  Constrained opBinary(string op)(T rhs) {
      return Constrained(mixin("this._value"~op~"rhs"));
  }
  ref Constrained opUnary(string op)() if(op=="++"||op=="--"){
      mixin(op~"this._value;");
      return this;
  }
  ref Constrained opAssign(T rhs) {
      value = rhs;
      return this;
  }
  ref Constrained opAssign(Constrained rhs) {
      value = rhs._value;
      return this;
  }

  @property T value() const  { return _value; }
  @property void value(T newValue) { _value = newValue; }

  alias this value;
}

Constrained!(T,pred) constrained(alias pred, T)(T _value){
   return typeof(return)(_value);
}

void main(){
  auto a = constrained!(x => x > 0)(1);
  auto b = a;
  auto c = b+1;
  auto d = c+a;
  a = b-d;
}
June 17, 2012
Re: Proposal to add 'Elements of Programming' Concepts to std.traits
On 06/17/12 14:23, Philippe Sigaud wrote:
> An obvious generalization is to template the struct on a predicate:
> 
> struct Constrained(T, alias pred) {
>    private T _value;
> 
>    invariant() { assert(pred(_value)); }
> 
>    this(T x) { _value = x; }
>    this(Constrained c) { _value = c._value; }
> 
>    Constrained opBinary(string op)(const ref Constrained rhs) {
>        return Constrained(mixin("this._value"~op~"rhs._value"));
>    }
>    Constrained opBinary(string op)(T rhs) {
>        return Constrained(mixin("this._value"~op~"rhs"));
>    }
>    ref Constrained opUnary(string op)() if(op=="++"||op=="--"){
>        mixin(op~"this._value;");
>        return this;
>    }
>    ref Constrained opAssign(T rhs) {
>        value = rhs;
>        return this;
>    }
>    ref Constrained opAssign(Constrained rhs) {
>        value = rhs._value;
>        return this;
>    }
> 
>    @property T value() const  { return _value; }
>    @property void value(T newValue) { _value = newValue; }
> 
>    alias this value;
> }
> 
> Constrained!(T,pred) constrained(alias pred, T)(T _value){
>     return typeof(return)(_value);
> }
> 
> void main(){
>    auto a = constrained!(x => x > 0)(1);
>    auto b = a;
>    auto c = b+1;
>    auto d = c+a;
>    a = b-d;
> }

Very nice :)
June 17, 2012
Re: Proposal to add 'Elements of Programming' Concepts to std.traits
On 6/17/12 1:38 AM, Philippe Sigaud wrote:
> On Sat, Jun 16, 2012 at 9:22 PM, bearophile<bearophileHUGS@lycos.com>  wrote:
>
>> I see. is that semantically different from this (beside being shorter)?
>>
>> struct NoZero {
>>     int value;
>>     this(int x) { value = x; }
>>     alias value this;
>>     invariant() { assert(value != 0); }
>> }
>> void main() {
>>     auto a = NoZero(5);
>>     auto b = NoZero(0);
>> }
>
> The invariant isn't invoked through alias this, it seems:
>
> void main() {
>     auto a = NoZero(5);
>     a = 0; // compiles and runs happily
> }

To avoid this, expose an rvalue via alias this, not an lvalue. Then 
implement opAssign etc.

Andrei
June 17, 2012
Re: Proposal to add 'Elements of Programming' Concepts to std.traits
On Sun, Jun 17, 2012 at 3:11 PM, Guillaume Chatelet
<chatelet.guillaume@gmail.com> wrote:
> On 06/17/12 14:23, Philippe Sigaud wrote:

>> void main(){
>>    auto a = constrained!(x => x > 0)(1);
>>    auto b = a;
>>    auto c = b+1;
>>    auto d = c+a;
>>    a = b-d; // Boom!
>> }
>
> Very nice :)

The new syntax for lambdas is delightful to use. A bunch of aliases
should give you the X10 examples.

x => ... still has some problem as it's a template, but using a
standard module-level function gives functionalities akin to X10:

bool pos(int x) { return x > 0;}
alias Constrained!(int, pos) Positive; // works

// alias Constrained!(int, (int x) { return x > 0;}) Positive; // works
// alias Constrained!(int, (int x) => x > 0) Positive; // works
// but:
// alias Constrained!(int, (x) { return x > 0;}) Positive; // ka-boom!
// alias Constrained!(int, x => x > 0) Positive; // no such luck



enum OK = Positive(1); // OK
enum NOK = Positive(-1); // Compiling error, cool!

So this works. That's nice to know, I never used an assert inside a CT
evaluation.

Hmmm, validating XML and/or SQL queries at CT...
June 17, 2012
Re: Proposal to add 'Elements of Programming' Concepts to std.traits
On 06/17/12 15:53, Philippe Sigaud wrote:
> x => ... still has some problem as it's a template, but using a
> standard module-level function gives functionalities akin to X10:
> 
> bool pos(int x) { return x > 0;}
> alias Constrained!(int, pos) Positive; // works
> 
> // alias Constrained!(int, (int x) { return x > 0;}) Positive; // works
> // alias Constrained!(int, (int x) => x > 0) Positive; // works
> // but:
> // alias Constrained!(int, (x) { return x > 0;}) Positive; // ka-boom!
> // alias Constrained!(int, x => x > 0) Positive; // no such luck

I ran into that problem also. I usually tend to define a function for
readability. It would be nice to have it working though, the last one is
definitely neat.

> enum OK = Positive(1); // OK
> enum NOK = Positive(-1); // Compiling error, cool!
> 
> So this works. That's nice to know, I never used an assert inside a CT
> evaluation.
> 
> Hmmm, validating XML and/or SQL queries at CT...

Yummy !
June 17, 2012
Re: Proposal to add 'Elements of Programming' Concepts to std.traits
On 6/16/12 10:26 AM, Guillaume Chatelet wrote:
> 'Elements of Programming' is an amazing book by Alexander Stepanov and
> Paul McJones ( M. Stepanov is the primary designer of the C++ STL ).
[snip]
> So without further ado, here is my humble first attempt
> https://github.com/gchatelet/phobos/blob/traits_concepts/std/traits2.d
> And the associated more readable DDoc
> http://bbteam.fr/traits2.html
>
> I would like to hear what you think.

This is a good idea because the traits are useful within and outside the 
algorithms discussed in EoP.

However, I don't think we need to abide strictly to the nomenclature 
(e.g. some of the stuff in EoP was already defined with a different 
name) although some EoP names are more mathematicky (such as "Codomain" 
vs. "ReturnType"). One issue is when EoP goes off and defines its own 
terms such as "regular type", which is usually known as "value type". In 
fact, "regular type" means something completely different in PL 
research. EoP's terminology didn't catch up outside C++ and sometimes 
outside a small group within it.

If I'm allowed to venture an opinion on EoP itself, it's an interesting 
book but I don't find it as big or great as some of its fans believe. 
It's not breaking any new ground, instead it explores more along already 
well-trodden territory, and it fails to find new mother lodes. Some 
(many?) chapters (such as transformations and orbits) describe some 
self-important notions but fail to demonstrate their general 
applicability. Nevertheless, the code really is exquisitely written, and 
studying it has significantly changed my approach and style in 
implementing algorithms.


Andrei
1 2 3 4
Top | Discussion index | About this forum | D home