www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Delegate function access to classes local variable

reply "Colin Grogan" <grogan.colin gmail.com> writes:
Hi folks,

I'm having some issue getting a delegate function access to a 
classes member variable.

At object construct time, I'm passing in a delegate function, and 
a list of parameters after.
The parameters are saved to a variable called vars.
Should I then not be able to access that vars variable from 
inside my delegate function?

I guess some code is a better explanation:
import std.stdio;
void main()
{
	Column!string col1 = new Column!string( {return "test"; }, 
"Hello, ");
	Column!string col2 = new Column!string( {return vars[0]; }, 
"World"); // Compilation fail!! Delegate cant see vars[0]
	writef("%s", col1.nextValue);
	writefln("%s", col2.nextValue);
// I want it to print "Hello, World" here
}

public class Column(Vars...){
	private Vars vars;
	public string delegate() func;
	
	public this(string delegate() func, Vars vars){
		this.vars = vars;
		this.func = func;
	}
	
	public string nextValue(){
		return this.func();
	}
}


The compilation error is:
source/app.d(5): Error: undefined identifier vars

This has been wrecking my head for a couple days now, I'm half 
way resigned to the fact it cant work but said I'd ask here to be 
sure.

Thanks!
Nov 08 2013
next sibling parent reply "Dicebot" <public dicebot.lv> writes:
On Friday, 8 November 2013 at 12:43:37 UTC, Colin Grogan wrote:
 import std.stdio;
 void main()
 {
 	Column!string col1 = new Column!string( {return "test"; }, 
 "Hello, ");
 	Column!string col2 = new Column!string( {return vars[0]; }, 
 "World"); // Compilation fail!! Delegate cant see vars[0]
 	writef("%s", col1.nextValue);
 	writefln("%s", col2.nextValue);
 // I want it to print "Hello, World" here
 }
Delegate refers to context it was created in. Your delegates are created in `main()` scope/context and thus can only access its stack frame. You can't access caller context from delegates.
Nov 08 2013
parent "Colin Grogan" <grogan.colin gmail.com> writes:
On Friday, 8 November 2013 at 13:10:10 UTC, Dicebot wrote:
 On Friday, 8 November 2013 at 12:43:37 UTC, Colin Grogan wrote:
 import std.stdio;
 void main()
 {
 	Column!string col1 = new Column!string( {return "test"; }, 
 "Hello, ");
 	Column!string col2 = new Column!string( {return vars[0]; }, 
 "World"); // Compilation fail!! Delegate cant see vars[0]
 	writef("%s", col1.nextValue);
 	writefln("%s", col2.nextValue);
 // I want it to print "Hello, World" here
 }
Delegate refers to context it was created in. Your delegates are created in `main()` scope/context and thus can only access its stack frame. You can't access caller context from delegates.
Ok, that clarifies that then :( Is there any alternative to using delegates for this behaviour? i.e. passing a function at object construct time, and let that function have access to the objects members?
Nov 08 2013
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 11/08/2013 01:43 PM, Colin Grogan wrote:
 Hi folks,

 I'm having some issue getting a delegate function access to a classes
 member variable.

 At object construct time, I'm passing in a delegate function, and a list
 of parameters after.
 The parameters are saved to a variable called vars.
 Should I then not be able to access that vars variable from inside my
 delegate function?

 I guess some code is a better explanation:
 import std.stdio;
 void main()
 {
      Column!string col1 = new Column!string( {return "test"; }, "Hello, ");
      Column!string col2 = new Column!string( {return vars[0]; },
 "World"); // Compilation fail!! Delegate cant see vars[0]
It is not even in scope here.
      writef("%s", col1.nextValue);
      writefln("%s", col2.nextValue);
 // I want it to print "Hello, World" here
 }

 public class Column(Vars...){
      private Vars vars;
      public string delegate() func;

      public this(string delegate() func, Vars vars){
          this.vars = vars;
          this.func = func;
      }

      public string nextValue(){
          return this.func();
      }
 }


 The compilation error is:
 source/app.d(5): Error: undefined identifier vars

 This has been wrecking my head for a couple days now, I'm half way
 resigned to the fact it cant work but said I'd ask here to be sure.

 Thanks!
import std.stdio; void main(){ Column!string col1 = new Column!string((ref m)=>"Hello, ", "test"); Column!string col2 = new Column!string((ref m)=>m.vars[0], "World"); writef("%s", col1.nextValue); writefln("%s", col2.nextValue); } public class Column(Vars...){ struct Members{ Vars vars; } private Members members; alias members this; string delegate(ref Members) func; this(string delegate(ref Members) func, Vars vars){ this.vars = vars; this.func = func; } string nextValue(){ return func(members); } }
Nov 08 2013
parent reply "Colin Grogan" <grogan.colin gmail.com> writes:
On Friday, 8 November 2013 at 13:14:33 UTC, Timon Gehr wrote:
 On 11/08/2013 01:43 PM, Colin Grogan wrote:
 Hi folks,

 I'm having some issue getting a delegate function access to a 
 classes
 member variable.

 At object construct time, I'm passing in a delegate function, 
 and a list
 of parameters after.
 The parameters are saved to a variable called vars.
 Should I then not be able to access that vars variable from 
 inside my
 delegate function?

 I guess some code is a better explanation:
 import std.stdio;
 void main()
 {
     Column!string col1 = new Column!string( {return "test"; }, 
 "Hello, ");
     Column!string col2 = new Column!string( {return vars[0]; },
 "World"); // Compilation fail!! Delegate cant see vars[0]
It is not even in scope here.
     writef("%s", col1.nextValue);
     writefln("%s", col2.nextValue);
 // I want it to print "Hello, World" here
 }

 public class Column(Vars...){
     private Vars vars;
     public string delegate() func;

     public this(string delegate() func, Vars vars){
         this.vars = vars;
         this.func = func;
     }

     public string nextValue(){
         return this.func();
     }
 }


 The compilation error is:
 source/app.d(5): Error: undefined identifier vars

 This has been wrecking my head for a couple days now, I'm half 
 way
 resigned to the fact it cant work but said I'd ask here to be 
 sure.

 Thanks!
import std.stdio; void main(){ Column!string col1 = new Column!string((ref m)=>"Hello, ", "test"); Column!string col2 = new Column!string((ref m)=>m.vars[0], "World"); writef("%s", col1.nextValue); writefln("%s", col2.nextValue); } public class Column(Vars...){ struct Members{ Vars vars; } private Members members; alias members this; string delegate(ref Members) func; this(string delegate(ref Members) func, Vars vars){ this.vars = vars; this.func = func; } string nextValue(){ return func(members); } }
Ah, brilliant! I like that construct. Thank you!
Nov 08 2013
parent reply "Colin Grogan" <grogan.colin gmail.com> writes:
On Friday, 8 November 2013 at 13:19:05 UTC, Colin Grogan wrote:
 On Friday, 8 November 2013 at 13:14:33 UTC, Timon Gehr wrote:
 On 11/08/2013 01:43 PM, Colin Grogan wrote:
 Hi folks,

 I'm having some issue getting a delegate function access to a 
 classes
 member variable.

 At object construct time, I'm passing in a delegate function, 
 and a list
 of parameters after.
 The parameters are saved to a variable called vars.
 Should I then not be able to access that vars variable from 
 inside my
 delegate function?

 I guess some code is a better explanation:
 import std.stdio;
 void main()
 {
    Column!string col1 = new Column!string( {return "test"; }, 
 "Hello, ");
    Column!string col2 = new Column!string( {return vars[0]; },
 "World"); // Compilation fail!! Delegate cant see vars[0]
It is not even in scope here.
    writef("%s", col1.nextValue);
    writefln("%s", col2.nextValue);
 // I want it to print "Hello, World" here
 }

 public class Column(Vars...){
    private Vars vars;
    public string delegate() func;

    public this(string delegate() func, Vars vars){
        this.vars = vars;
        this.func = func;
    }

    public string nextValue(){
        return this.func();
    }
 }


 The compilation error is:
 source/app.d(5): Error: undefined identifier vars

 This has been wrecking my head for a couple days now, I'm 
 half way
 resigned to the fact it cant work but said I'd ask here to be 
 sure.

 Thanks!
import std.stdio; void main(){ Column!string col1 = new Column!string((ref m)=>"Hello, ", "test"); Column!string col2 = new Column!string((ref m)=>m.vars[0], "World"); writef("%s", col1.nextValue); writefln("%s", col2.nextValue); } public class Column(Vars...){ struct Members{ Vars vars; } private Members members; alias members this; string delegate(ref Members) func; this(string delegate(ref Members) func, Vars vars){ this.vars = vars; this.func = func; } string nextValue(){ return func(members); } }
Ah, brilliant! I like that construct. Thank you!
My optimism may have been premature. After trying this out today, I havent been able to pass in anything more complex than a 1 line to the constructor. For example, Column!(int, int) randonNumberColumn = new Column!(int, int)((ref m)=>to!string(uniform(m.vars[0], m.vars[1])), 1, 10); will work. However, Column!(int, int) incrementalNumberColumn = new Column!(int, int)((ref m)=>{m.vars[0]+=m.vars[1]; return to!string(m.vars[0]-m.vars[1]);}, 1,2); wont. Maybe my syntax is just wrong or this is simply a limitation? Also, if you could explain what the => operator is doing there that would be great. I couldnt find the info on it in the docs...
Nov 10 2013
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 11/10/2013 09:03 PM, Colin Grogan wrote:
 For example,
      Column!(int, int) randonNumberColumn = new Column!(int, int)((ref
 m)=>to!string(uniform(m.vars[0], m.vars[1])), 1, 10);

 will work.
 However,
      Column!(int, int) incrementalNumberColumn = new Column!(int,
 int)((ref m)=>{m.vars[0]+=m.vars[1]; return
 to!string(m.vars[0]-m.vars[1]);}, 1,2);

 wont.

 Maybe my syntax is just wrong or this is simply a limitation?
This will work: Column!(int, int) incrementalNumberColumn = new Column!(int, int)((ref m){m.vars[0]+=m.vars[1];return to!string(m.vars[0]-m.vars[1]);}, 1,2);
 Also, if you could explain what the => operator is doing there that
 would be great. I couldnt find the info on it in the docs...
(ref m)=>exp is the same as (ref m){ return exp; } http://dlang.org/expression.html#Lambda (hence (ref m)=>{return exp; } which is the same as (ref m)=>(){ return exp; } is the same as (ref m)=>()=>exp the return type of this expression is 'string delegate()' instead of string and therefore the compiler rejects your code.)
Nov 10 2013