www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Error: 'this' is only defined in non-static member functions,

reply Matej Nanut <matejnanut gmail.com> writes:
Hey everyone,

I, once again, have a problem with an error I can't seem to figure out!

The situation:
- a class, inherited by five other classes;
- the class having a static function which returns one
  if its subclasses depending on the input of a string.

Something like this:

class Node
{
  static Node parse(ref string s)
  {
    /* Get value to switch by, an enum. */
    auto switchable = /* ... */;
    final switch (switchable)
    {
      case Blah.one: return new OneNode(s);
      case Blah.two: return new TwoNode(s);
    /* ... */
    }
  }
}

And I get the mentioned error. I don't understand it:
is it saying I'm using `this' in a static member function
called `parse'? Am I insane; where am I referencing it?

The other classes are in this form:

class OneNode : Node
{
  /* ... stuff ... */
  this(ref string s)
  {
    /* Does stuff with `s'. */
  }
}

Do you need more information?

Thank you,
Matej
Jan 16 2012
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 01/17/2012 12:49 AM, Matej Nanut wrote:
 Hey everyone,

 I, once again, have a problem with an error I can't seem to figure out!

 The situation:
 - a class, inherited by five other classes;
 - the class having a static function which returns one
    if its subclasses depending on the input of a string.

 Something like this:

 class Node
 {
    static Node parse(ref string s)
    {
      /* Get value to switch by, an enum. */
      auto switchable = /* ... */;
      final switch (switchable)
      {
        case Blah.one: return new OneNode(s);
        case Blah.two: return new TwoNode(s);
      /* ... */
      }
    }
 }

 And I get the mentioned error. I don't understand it:
 is it saying I'm using `this' in a static member function
 called `parse'? Am I insane; where am I referencing it?

 The other classes are in this form:

 class OneNode : Node
 {
    /* ... stuff ... */
    this(ref string s)
    {
      /* Does stuff with `s'. */
    }
 }

 Do you need more information?

snippet given which exhibits the problematic behavior in question.
Jan 16 2012
next sibling parent =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= <xtzgzorex gmail.com> writes:
On 17-01-2012 12:23, Matej Nanut wrote:
 I will try to remove all snippets in my code that aren't relevant but still
 exhibit the issue, when I find the time. What I forgot to mention is that
 this error appeared when I did some so-called "refactoring"; I moved a
 nested class out of its parent, since I wanted it visible on the outside.

 I moved it back now and reference it by Parent.Child.<stuff>, which is
 just as good, and the error isn't there anymore, but I still don't understand
 it. I must have missed some variable renaming or something. Or I was
 just plain sloppy. As mentioned I will post a complete snippet with the
 error sometime until friday.

 On 17 January 2012 02:33, Timon Gehr<timon.gehr gmx.ch>  wrote:
 On 01/17/2012 12:49 AM, Matej Nanut wrote:
 Hey everyone,

 I, once again, have a problem with an error I can't seem to figure out!

 The situation:
 - a class, inherited by five other classes;
 - the class having a static function which returns one
    if its subclasses depending on the input of a string.

 Something like this:

 class Node
 {
    static Node parse(ref string s)
    {
      /* Get value to switch by, an enum. */
      auto switchable = /* ... */;
      final switch (switchable)
      {
        case Blah.one: return new OneNode(s);
        case Blah.two: return new TwoNode(s);
      /* ... */
      }
    }
 }

 And I get the mentioned error. I don't understand it:
 is it saying I'm using `this' in a static member function
 called `parse'? Am I insane; where am I referencing it?

 The other classes are in this form:

 class OneNode : Node
 {
    /* ... stuff ... */
    this(ref string s)
    {
      /* Does stuff with `s'. */
    }
 }

 Do you need more information?

given which exhibits the problematic behavior in question.


DustMite is good for making test cases: https://github.com/CyberShadow/DustMite -- - Alex
Jan 17 2012
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 01/17/2012 06:02 PM, Matej Nanut wrote:
 On 17 January 2012 16:54, H. S. Teoh<hsteoh quickfur.ath.cx>  wrote:
 This may be the cause of your trouble. If the nested class references
 members in the outer class, then moving it outside will break it, since
 it won't have an outer scope anymore.


 T

 --
 Only boring people get bored. -- JM

That was my guess too — but I'm not referencing the outer class. The outer class is just using instances of the inner one. Also, the line number of the error points to ‘new’ statements in the static method. (The calls which instantiate subclasses of the inner class.) If I do "return null" it works as well, without complaining. So it's not a referencing issue I think. As you all seem eager to help, I will copy the entire class, without subclasses, to here. I will be grateful for any comments regarding the current issue at hand or about the code in general. The ‘new’-ed Nodes are defined like ‘class CostNode : Node { ... }’. Another note, the outer class is an inner class of another class as well, if that makes a difference. Also, the outer class isn't really a class, it's a struct, but renaming that to ‘class’ doesn't change anything either. ---- code begin ---- class Node { static Node parse(ref string line) { string mnemonic = munch(line, "A-Z"); line = line.stripLeft(); auto op = mnemonic in mnemonics; if (!op) throw new Exception("Unknown mnemonic: `" ~ mnemonic ~"'"); final switch (*op) { case NodeType.COST: return new CostNode(line); case NodeType.PAUSE: return new PauseNode(line); case NodeType.COLDR: return new ColDrNode(line); case NodeType.COLRA: return new ColRaNode(line); case NodeType.DROP: return new DropNode(line); case NodeType.RAISE: return new RaiseNode(line); } /* Doing something like `return new Node()' doesn't work either. * Only `return null' works here. */ } enum NodeType : ubyte { COST, PAUSE, COLDR, COLRA, DROP, RAISE } static immutable NodeType[string] mnemonics; static this() { mnemonics = [ "COST" : NodeType.COST, "PAUSE" : NodeType.PAUSE, "COLDR" : NodeType.COLDR, "COLRA" : NodeType.COLRA, "DROP" : NodeType.DROP, "RAISE" : NodeType.RAISE ]; } } ---- code end ----

I'm quite sure that the error in your code occurs for the same reason as in the following code snippet: class C{ class D{} static make(){return new D();} // error } You can fix it by making D static: class C{ static class D{} static make(){return new D();} // ok } The reason is that non-static inner classes have an implicit 'outer' property that links to the class it was created with. Therefore, to construct them inside a member function, the implicit 'this' pointer is needed. If the 'outer' property is actually unwanted, it is best to declare inner classes as static.
Jan 17 2012
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 01/17/2012 07:13 PM, Matej Nanut wrote:
 On 17 January 2012 19:07, H. S. Teoh<hsteoh quickfur.ath.cx>  wrote:
 Andrei's book ("The D Programming Language") is quite thorough in
 explaining these D constructs. It's a highly recommended buy if you're
 doing serious work in D.


 T

 --
 The two rules of success: 1. Don't tell everything you know. -- YHL

I've been thinking on getting that for a while now. How up to date is it?

I think it is mostly in a good state. There are a few errata and some unmentioned features because D is/was somewhat of a moving/improving target. On the other hand, many recent bug fixes were targeted at making the implementation consistent with the specification in TDPL.
 Or does it explain such general concepts that I shouldn't be worried
 about that at all?

I don't think you need to be worried, just be prepared that a few code samples may not compile without minimal fixes.
 Everyone seems to be recommending it so I don't see
 why I shouldn't get it. A free university period is also coming up, so that
 might be a great way to spend my available time.

Indeed. When I read it, I have found my time well spent. It is very well written.
 I'm definitely serious about learning and using D. I've been impressed with
 it since I first saw it and I intend to do as much work with it as possible.
 I'm not _doing_ any serious work with it yet, though. In fact, none of the work
 I do could be considered very serious at all. :)

Jan 17 2012
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 01/17/2012 06:58 PM, Matej Nanut wrote:
 On 17 January 2012 18:29, Timon Gehr<timon.gehr gmx.ch>  wrote:
 I'm quite sure that the error in your code occurs for the same reason as in
 the following code snippet:

 class C{
     class D{}
     static make(){return new D();} // error
 }

 You can fix it by making D static:

 class C{
     static class D{}
     static make(){return new D();} // ok
 }

 The reason is that non-static inner classes have an implicit 'outer'
 property that links to the class it was created with. Therefore, to
 construct them inside a member function, the implicit 'this' pointer is
 needed. If the 'outer' property is actually unwanted, it is best to declare
 inner classes as static.

Yes! If I move the class and its subclasses out of its outer class, and declare them all static, it works! Note that your `make' function is being called within class `D' in my example, if I replace the names. However, the same thing applies. Your explanation was nice, but now I'd like to know what the difference of a non-static vs. a static class is, if they're defined top-level? Or are they then the same?

Indeed they are the same. Anything top-level is implicitly static in D.
 I don't expect anyone to thoroughly explain things to me, but
 pointing out a good source, like a link or a book, would be really helpful.

I don't know if there is any, but I can explain to you the difference between static and non-static nested classes in detail: class A{ int x; static class B{void echo(){writeln(x);}} // n.g. } class A{ int x; class B{void echo(){writeln(x);}} // ok } In other words, non-static nested classes can reference non-static fields of the enclosing class. In order to provide that functionality, non-static nested classes need the implicit 'outer' field. The first snippet is effectively rewritten to something like the following: class A{ int x; class B{A __outer; void echo(){writeln(__outer.x);} } Therefore, for constructing a class instance of type A.B, an instance of A must be provided as an initializer for the 'outer' field. If an instance of B is created in a member of A, the 'this' pointer gets used (and hence is required to be present), but you can also do: void main() { auto a = new A; auto b = a.new B; // construct an 'A.B' with 'a' in implicit 'outer' field a.x = 100; b.echo(); // writes '100' } This is probably one of the more obscure features of D. =)
 I lack general knowledge in the OOP area and must really learn more about
 it, as I've always been programming in C and could easily get away with it
 as we were doing small-ish programs at university.

Jan 17 2012
prev sibling next sibling parent Matej Nanut <matejnanut gmail.com> writes:
I will try to remove all snippets in my code that aren't relevant but still
exhibit the issue, when I find the time. What I forgot to mention is that
this error appeared when I did some so-called "refactoring"; I moved a
nested class out of its parent, since I wanted it visible on the outside.

I moved it back now and reference it by Parent.Child.<stuff>, which is
just as good, and the error isn't there anymore, but I still don't understa=
nd
it. I must have missed some variable renaming or something. Or I was
just plain sloppy. As mentioned I will post a complete snippet with the
error sometime until friday.

On 17 January 2012 02:33, Timon Gehr <timon.gehr gmx.ch> wrote:
 On 01/17/2012 12:49 AM, Matej Nanut wrote:
 Hey everyone,

 I, once again, have a problem with an error I can't seem to figure out!

 The situation:
 - a class, inherited by five other classes;
 - the class having a static function which returns one
 =C2=A0 if its subclasses depending on the input of a string.

 Something like this:

 class Node
 {
 =C2=A0 static Node parse(ref string s)
 =C2=A0 {
 =C2=A0 =C2=A0 /* Get value to switch by, an enum. */
 =C2=A0 =C2=A0 auto switchable =3D /* ... */;
 =C2=A0 =C2=A0 final switch (switchable)
 =C2=A0 =C2=A0 {
 =C2=A0 =C2=A0 =C2=A0 case Blah.one: return new OneNode(s);
 =C2=A0 =C2=A0 =C2=A0 case Blah.two: return new TwoNode(s);
 =C2=A0 =C2=A0 /* ... */
 =C2=A0 =C2=A0 }
 =C2=A0 }
 }

 And I get the mentioned error. I don't understand it:
 is it saying I'm using `this' in a static member function
 called `parse'? Am I insane; where am I referencing it?

 The other classes are in this form:

 class OneNode : Node
 {
 =C2=A0 /* ... stuff ... */
 =C2=A0 this(ref string s)
 =C2=A0 {
 =C2=A0 =C2=A0 /* Does stuff with `s'. */
 =C2=A0 }
 }

 Do you need more information?


 given which exhibits the problematic behavior in question.

Jan 17 2012
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Jan 17, 2012 at 12:23:55PM +0100, Matej Nanut wrote:
 I will try to remove all snippets in my code that aren't relevant but still
 exhibit the issue, when I find the time. What I forgot to mention is that
 this error appeared when I did some so-called "refactoring"; I moved a
 nested class out of its parent, since I wanted it visible on the outside.

This may be the cause of your trouble. If the nested class references members in the outer class, then moving it outside will break it, since it won't have an outer scope anymore. T -- Only boring people get bored. -- JM
Jan 17 2012
prev sibling next sibling parent Matej Nanut <matejnanut gmail.com> writes:
On 17 January 2012 16:54, H. S. Teoh <hsteoh quickfur.ath.cx> wrote:
 This may be the cause of your trouble. If the nested class references
 members in the outer class, then moving it outside will break it, since
 it won't have an outer scope anymore.


 T

 --
 Only boring people get bored. -- JM

That was my guess too =E2=80=94 but I'm not referencing the outer class. Th= e outer class is just using instances of the inner one. Also, the line number of the error points to =E2=80=98new=E2=80=99 statements in the static metho= d. (The calls which instantiate subclasses of the inner class.) If I do "return null" it works as well, without complaining. So it's not a referencing issue I think= . As you all seem eager to help, I will copy the entire class, without subclasses, to here. I will be grateful for any comments regarding the current issue at hand or about the code in general. The =E2=80=98new=E2=80=99-ed Nodes are defined like =E2=80=98class CostNode= : Node { ... }=E2=80=99. Another note, the outer class is an inner class of another class as well, if that makes a difference. Also, the outer class isn't really a class, it'= s a struct, but renaming that to =E2=80=98class=E2=80=99 doesn't change anyth= ing either. ---- code begin ---- class Node { static Node parse(ref string line) { string mnemonic =3D munch(line, "A-Z"); line =3D line.stripLeft(); auto op =3D mnemonic in mnemonics; if (!op) throw new Exception("Unknown mnemonic: `" ~ mnemonic ~"= '"); final switch (*op) { case NodeType.COST: return new CostNode(line); case NodeType.PAUSE: return new PauseNode(line); case NodeType.COLDR: return new ColDrNode(line); case NodeType.COLRA: return new ColRaNode(line); case NodeType.DROP: return new DropNode(line); case NodeType.RAISE: return new RaiseNode(line); } /* Doing something like `return new Node()' doesn't work ei= ther. * Only `return null' works here. */ } enum NodeType : ubyte { COST, PAUSE, COLDR, COLRA, DROP, RAISE } static immutable NodeType[string] mnemonics; static this() { mnemonics =3D [ "COST" : NodeType.COST, "PAUSE" : NodeType.PAUSE, "COLDR" : NodeType.COLDR, "COLRA" : NodeType.COLRA, "DROP" : NodeType.DROP, "RAISE" : NodeType.RAISE ]; } } ---- code end ----
Jan 17 2012
prev sibling next sibling parent Matej Nanut <matejnanut gmail.com> writes:
On 17 January 2012 18:29, Timon Gehr <timon.gehr gmx.ch> wrote:
 I'm quite sure that the error in your code occurs for the same reason as =

 the following code snippet:

 class C{
 =C2=A0 =C2=A0class D{}
 =C2=A0 =C2=A0static make(){return new D();} // error
 }

 You can fix it by making D static:

 class C{
 =C2=A0 =C2=A0static class D{}
 =C2=A0 =C2=A0static make(){return new D();} // ok
 }

 The reason is that non-static inner classes have an implicit 'outer'
 property that links to the class it was created with. Therefore, to
 construct them inside a member function, the implicit 'this' pointer is
 needed. If the 'outer' property is actually unwanted, it is best to decla=

 inner classes as static.

Yes! If I move the class and its subclasses out of its outer class, and dec= lare them all static, it works! Note that your `make' function is being called within class `D' in my examp= le, if I replace the names. However, the same thing applies. Your explanation was nice, but now I'd like to know what the difference of = a non-static vs. a static class is, if they're defined top-level? Or are they= then the same? I don't expect anyone to thoroughly explain things to me, but pointing out a good source, like a link or a book, would be really helpful. I lack general knowledge in the OOP area and must really learn more about it, as I've always been programming in C and could easily get away with it as we were doing small-ish programs at university.
Jan 17 2012
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Jan 17, 2012 at 06:58:55PM +0100, Matej Nanut wrote:
[...]
 Your explanation was nice, but now I'd like to know what the
 difference of a non-static vs. a static class is, if they're defined
 top-level? Or are they then the same? I don't expect anyone to
 thoroughly explain things to me, but pointing out a good source, like
 a link or a book, would be really helpful.

Andrei's book ("The D Programming Language") is quite thorough in explaining these D constructs. It's a highly recommended buy if you're doing serious work in D. T -- The two rules of success: 1. Don't tell everything you know. -- YHL
Jan 17 2012
prev sibling next sibling parent Matej Nanut <matejnanut gmail.com> writes:
On 17 January 2012 19:07, H. S. Teoh <hsteoh quickfur.ath.cx> wrote:
 Andrei's book ("The D Programming Language") is quite thorough in
 explaining these D constructs. It's a highly recommended buy if you're
 doing serious work in D.


 T

 --
 The two rules of success: 1. Don't tell everything you know. -- YHL

I've been thinking on getting that for a while now. How up to date is it? Or does it explain such general concepts that I shouldn't be worried about that at all? Everyone seems to be recommending it so I don't see why I shouldn't get it. A free university period is also coming up, so that might be a great way to spend my available time. I'm definitely serious about learning and using D. I've been impressed with it since I first saw it and I intend to do as much work with it as possible. I'm not _doing_ any serious work with it yet, though. In fact, none of the work I do could be considered very serious at all. :)
Jan 17 2012
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Tuesday, January 17, 2012 19:13:02 Matej Nanut wrote:
 I've been thinking on getting that for a while now. How up to date is it?
 Or does it explain such general concepts that I shouldn't be worried
 about that at all? Everyone seems to be recommending it so I don't see
 why I shouldn't get it. A free university period is also coming up, so that
 might be a great way to spend my available time.

If anything, it's _too_ up-to-date. There are a few relatively minor changes which have been made to the language since its release (e.g. weak vs strong purity and attribute inference for templated functions), but for the most part if TDPL doesn't match what dmd is doing, it's because features aren't fully implemented yet which should be (e.g. alias this works, but according to TDPL, you should be able to have multiple alias this-es per type - which you can't currently do). There has been a recent push though to fix the remaining issues where the compiler doesn't yet match TDPL. I actually think that TDPL is the best programming language book that I've ever read. It's very well written and _way_ more informative than the rather sparse online documentation. I'd been programming in D for a while when I read it, and there were all kinds of stuff in there that I didn't know about. I really think that it's a must have for any serious D programmer. - Jonathan M Davis P.S. TDPL's errata is here: http://erdani.com/tdpl/errata/
Jan 17 2012
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Jan 17, 2012 at 07:13:02PM +0100, Matej Nanut wrote:
 On 17 January 2012 19:07, H. S. Teoh <hsteoh quickfur.ath.cx> wrote:
 Andrei's book ("The D Programming Language") is quite thorough in
 explaining these D constructs. It's a highly recommended buy if you're
 doing serious work in D.


 I've been thinking on getting that for a while now. How up to date is it?
 Or does it explain such general concepts that I shouldn't be worried
 about that at all? Everyone seems to be recommending it so I don't see
 why I shouldn't get it. A free university period is also coming up, so that
 might be a great way to spend my available time.

Well, D2 is a fast-evolving language, so any book can't possibly be 100% up to date. :) But having said that, what's covered in the book is pretty close to the current state of D2. The basics haven't changed, so you don't really have to worry about that. When you get to the level where it starts to matter, you probably don't need the book anymore (or only need it for reference) anyway. :)
 I'm definitely serious about learning and using D. I've been impressed
 with it since I first saw it and I intend to do as much work with it
 as possible.

I've also been impressed with D since I first stumbled across it late last year. I've been using C/C++ for almost 2 decades, but after tasting D's power in a recent small project, I have to confess that I just can't go back to C/C++ for my personal projects anymore. The more I use D the more I like it.
 I'm not _doing_ any serious work with it yet, though. In fact, none of
 the work I do could be considered very serious at all.  :)

Isn't that how we all start out, though? Tinker with the language in toy projects that eventually become the basis for something more serious. T -- 2+2=4. 2*2=4. 2^2=4. Therefore, +, *, and ^ are the same operation.
Jan 17 2012
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Jan 17, 2012 at 08:25:28PM +0100, Timon Gehr wrote:
[...]
 In other words, non-static nested classes can reference non-static
 fields of the enclosing class. [...]

 void main() {
     auto a = new A;
     auto b = a.new B; // construct an 'A.B' with 'a' in implicit
 'outer' field
     a.x = 100;
     b.echo(); // writes '100'
 }
 
 This is probably one of the more obscure features of D. =)

It totally makes sense though. In some of my past C++ projects, I've had to use the inner class idiom quite often. Of course, it's not directly supported by the language so I ended up writing lots of little nested classes like this: class outer { ... class inner1 { outer *ctxt; ... inner1(outer *c) : ctxt(c) {} }; ... class inner2 { outer *ctxt; ... inner2(outer *c) : ctxt(c) {} }; ... void f() { ... inner1 *helper1 = new inner1(this); register_callback(helper1, ...); ... inner2 *helper2 = new inner2(this); register_callback(helper2, ...); ... } }; After a while, it just got really really tedious to keep writing the same boilerplate code over and over again. In D, a lot of that redundancy can be gotten rid of (no need for explicit outer pointers in the inner classes, eliminate ctor parameters), just because (non-static) inner classes automatically get an outer pointer, and you can just instantiate them with: auto helper1 = this.new inner1; But D lets you do even better. Instead of creating an inner class, you can just pass a delegate to do what needs to be done: void f() { ... register_callback((args) { this.state1++; }, ...); register_callback((args) { this.state2++; }, ...); ... } Much more readable, and much less room for bugs to hide in. T -- "Maybe" is a strange word. When mom or dad says it it means "yes", but when my big brothers say it it means "no"! -- PJ jr.
Jan 17 2012
prev sibling parent Stewart Gordon <smjg_1998 yahoo.com> writes:
For future reference and to elaborate on what others have said, if you're
asking for help 
solving a problem with your code, then please:

1. Post a small, self-contained testcase that demonstrates the problem straight
out of the 
box.

Tips here:
http://www.sscce.org/

2. Post full compiler output (or runtime output, if it's a runtime problem)
from the testcase.

3. State what compiler version and operating system you are using, as it may be
relevant.

Stewart.
Jan 17 2012