www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 7603] New: Default initializer is allowed on ref/out params

reply d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7603

           Summary: Default initializer is allowed on ref/out params
           Product: D
           Version: D2
          Platform: All
        OS/Version: All
            Status: NEW
          Keywords: accepts-invalid
          Severity: normal
          Priority: P2
         Component: DMD
        AssignedTo: nobody puremagic.com
        ReportedBy: andrej.mitrovich gmail.com



18:44:34 PST ---
void test1(ref bool val = true) {
}

void test2(out bool val = true) {
}

void main()
{
    bool x;
    test1(x);  // compiles ok
    test2(x);  // compiles ok

    test1();  // Error: constant true is not an lvalue
    test2();  // Error: constant true is not an lvalue
}

The compiler should probably disallow that kind of function signature
regardless of any calls. The initializer doesn't really do anything.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Feb 27 2012
next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7603


bearophile_hugs eml.cc changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |bearophile_hugs eml.cc



Ow.

Even this fails:

void test1(ref int val = 10) {}
void test2(out int val = 20) {}
void main() {
    int x;
    test1(x);
    assert(x == 10);
    test2(x);
    assert(x == 20);
}

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Feb 27 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7603




10:34:29 PDT ---

 void test1(ref bool val = true) {
 }
 
 void test2(out bool val = true) {
 }
Actually I'm only half-right. Phobos uses this in std.random: void randomShuffle(Range, RandomGen = Random)(Range r, ref RandomGen gen = rndGen); So 'val' is either a reference to a passed-in argument, or a reference to the default argument which is an lvalue. Default argument for 'ref' parameter should only be allowed if the argument is an lvalue ('true' is an rvalue'). The compiler already checks this but *only* if the function is called without arguments: void test(ref bool val = true) { } void main() { bool b; test(b); // ok, no errors test(); // errors only on this invocation } The compiler should error as soon as it sees the invalid declaration. I'll make a pull shortly. Btw, the same applies to 'out'. An rvalue isn't valid, but an lvalue as default argument is perfectly valid: bool w = true; void test(out bool val = w) { } void main() { test(); assert(w == false); } -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Oct 04 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7603




See also Issue 5850

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Oct 04 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7603


Maxim Fomin <maxim maxim-fomin.ru> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |maxim maxim-fomin.ru



---

 Ow.
 
 Even this fails:
 
 void test1(ref int val = 10) {}
 void test2(out int val = 20) {}
 void main() {
     int x;
     test1(x);
     assert(x == 10);
     test2(x);
     assert(x == 20);
 }
Why wouldn't this fail? Default arguments are used if no argument is given. Sine you provide arguments and functions don't modify them, arguments are not changed. The only modification happens due to parameter storage class out. void test1(ref int val = 10) {} void test2(out int val = 20) {} void main() { int x = 5; test1(x); assert(x == 5); test2(x); assert(x == 0); } Passes both assertions as it should. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Oct 04 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7603




09:30:41 PDT ---

 Why wouldn't this fail? Default arguments are used if no argument is given.
 Sine you provide arguments and functions don't modify them, arguments are not
 changed. The only modification happens due to parameter storage class out.
 
  void test1(ref int val = 10) {}
  void test2(out int val = 20) {}
  void main() {
      int x = 5;
      test1(x);
      assert(x == 5);
      test2(x);
      assert(x == 0);
 }
 
 Passes both assertions as it should.
Ignoring what bear's confusion here, the function declaration is invalid. Call test1() alone: void test1(ref int val = 10) { } void main() { test1(); // Error: constant 10 is not an lvalue } It makes no sense adding default arguments if they'll never compile, so this needs to be a CT error when the function is parsed and not when the function is called. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Oct 05 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7603




---


 Why wouldn't this fail? Default arguments are used if no argument is given.
 Sine you provide arguments and functions don't modify them, arguments are not
 changed. The only modification happens due to parameter storage class out.
 
  void test1(ref int val = 10) {}
  void test2(out int val = 20) {}
  void main() {
      int x = 5;
      test1(x);
      assert(x == 5);
      test2(x);
      assert(x == 0);
 }
 
 Passes both assertions as it should.
Ignoring what bear's confusion here, the function declaration is invalid. Call test1() alone: void test1(ref int val = 10) { } void main() { test1(); // Error: constant 10 is not an lvalue } It makes no sense adding default arguments if they'll never compile, so this needs to be a CT error when the function is parsed and not when the function is called.
Agree here, but I was talking about that it is logically that those asserts should fail, rather than about accepting non-lvalue default arguments. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Oct 05 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7603




Commit pushed to master at https://github.com/D-Programming-Language/dmd

https://github.com/D-Programming-Language/dmd/commit/67681b916f7880432c7da14a714404af0254278e


Fix Issue 7603 - Default initializer for ref/out must be an lvalue

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Oct 06 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7603


yebblies <yebblies gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
                 CC|                            |yebblies gmail.com
         Resolution|                            |FIXED


-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Oct 07 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7603




14:04:47 PDT ---
I've just realized I shot myself in the foot with this change (well,
partially).

Direct snippet of some code I've used (the main thing to look for is "ref
Set!SymID oldIDs = Set!SymID.init")

    SymID[] getClassTreeImpl(Table)(Class par, Table table, ref Set!SymID
oldIDs = Set!SymID.init, bool skipRoot = false)
    {
        typeof(return) result;

        if (!skipRoot && par.ID !in oldIDs)
        {
            oldIDs.add(par.ID);
            result ~= par.ID;
        }

        foreach (ID, cls; table)
        {
            if (cls.baseIDs.canFind(par.ID))
                result ~= getClassTreeImpl(cls, table, oldIDs);
        }

        return result;
    }

Basically, getClassTreeImpl can be passed an existing set of keys or it will
create a new one if not provided and will update it during recursive calls.

I can fix my code, but I worry if my changeset is going to brake anyone elses
code. I wonder if this trick is used that often.. I guess we'll have to wait
and see.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Oct 07 2012
prev sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7603




01:38:35 PST ---
*** Issue 5850 has been marked as a duplicate of this issue. ***

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Dec 11 2012