www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Constructors not working

reply Svyat <giraffe.sleep yandex.ru> writes:
I write this code in one directory:

module time;

     struct Time {
         public int hours, minutes, seconds;
         this(int h, int m, int s) {
             hours = h;
             minutes = m;
             seconds = s;
         }
         Time opBinary(string op : "=")(int secos) {
             assert(secos <= 86_400);
             return new Time(secos / 3600, (secos % 3600) / 60, 
secos % 60);
         }
     }

module testfortime;
import time;
import std.stdio;

     void main() {
         Time time = 360;
         write(time.hours);
         readln;
     }


After execute 'dmd -run ./testfortime.d' i got this:
".\testfortime.d(6): Error: constructor `time.Time.this(int h, 
int m, int s)` is not callable using argument types `(int)`
.\testfortime.d(6):        too few arguments, expected `3`, got 
`1`"

WTF? Why standart constructor isn`t callable? How it`s possible 
in a programming language?
Sep 02 2022
next sibling parent reply rikki cattermole <rikki cattermole.co.nz> writes:
I think you are wanting opAssign not opBinary.

Also you made a mistake, since its a struct you don't want to new it 
when you construct and return it.

```d
return new Time(secos / 3600, (secos % 3600) / 60, secos % 60);
```

Would be a ``Time*`` not ``Time`` which is what you returned.
Sep 02 2022
parent Tejas <notrealemail gmail.com> writes:
On Friday, 2 September 2022 at 18:39:27 UTC, rikki cattermole 
wrote:
 I think you are wanting opAssign not opBinary.

 Also you made a mistake, since its a struct you don't want to 
 new it when you construct and return it.

 ```d
 return new Time(secos / 3600, (secos % 3600) / 60, secos % 60);
 ```

 Would be a ``Time*`` not ``Time`` which is what you returned.
And shouldn't an `opAssign` be `void` anyways? Doubt there's many people writing stuff like `auto c = (a = b);`, where `a` is a `struct`/`class`.
Sep 02 2022
prev sibling next sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 9/2/22 11:35, Svyat wrote:

          Time time = 360;
It seems to be more idiomatic to write it like this: auto time = Time(360); Or const, immutable, etc. const time = Time(360); // Now un-assignable But you would get the same compilation error. So, one way to work with it is to use default constructor arguments: this(int h, int m = 0, int s = 0) Then it would work with just 360.
 .\testfortime.d(6):        too few arguments, expected `3`, got `1`"
At least that one is helpful. There are much more cryptic error messages out there. :) Ali
Sep 02 2022
prev sibling next sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
I forgot to say that you don't need to write a constructor for most 
structs because Time's constructor-generated default constructor works 
like yours and with default arguments:

struct Time {
   public int hours, minutes, seconds;

   // No constructor needed here.

   // Note 'return this;' as the last statement would be
   // mimicing how fundamental types like 'int'
   // work. However, I am getting the following warning when
   // I do that:
   //
   //   Deprecation: returning `this` escapes a reference to
   //   parameter `this` perhaps annotate the function with
   //   `return`
   //
   // For simplicity, I will just return void in this code.
   //
   void opAssign(int secos) {
     assert(secos <= 86_400);
     hours = secos / 3600;
     minutes = (secos % 3600) / 60;
     seconds = secos % 60;
   }
}

import std.stdio;

void main() {
   auto time = Time(360);
   time = 12_345;
   writeln(time);
   readln;
}

Ali
Sep 02 2022
prev sibling parent Mathias LANG <pro.mathias.lang gmail.com> writes:
On Friday, 2 September 2022 at 18:35:22 UTC, Svyat wrote:
 I write this code in one directory:

 ```
 module time;

     struct Time {
         public int hours, minutes, seconds;
         this(int h, int m, int s) {
             hours = h;
             minutes = m;
             seconds = s;
         }
         Time opBinary(string op : "=")(int secos) {
             assert(secos <= 86_400);
             return new Time(secos / 3600, (secos % 3600) / 60, 
 secos % 60);
         }
     }
 ```

 ```
 module testfortime;
 import time;
 import std.stdio;

     void main() {
         Time time = 360;
         write(time.hours);
         readln;
     }
 ```

 After execute 'dmd -run ./testfortime.d' i got this:
 ```
 ".\testfortime.d(6): Error: constructor `time.Time.this(int h, 
 int m, int s)` is not callable using argument types `(int)`
 .\testfortime.d(6):        too few arguments, expected `3`, got 
 `1`"
 ```

 WTF? Why standart constructor isn`t callable? How it`s possible 
 in a programming language?
First of all, the error message is telling you what is wrong: You are calling the constructor with only one argument, while your constructor is declared to take 3. If you wanted your call to work, you should have declared the constructor as: ``` this(int h, int m = 0, int s = 0) { /* Magic */ } ``` But D will by default give you a default constructor that does exactly that. And the constructor will be properly attributed, because in your case, the constructor should actually be this: ``` this(int h, int m = 0, int s = 0) inout scope safe pure nothrow nogc { /* Magic */ } ``` So if you just remove the constructor, things will work. Note that in D, as soon as you define one constructor, the default one is no longer generated. Second, your `opBinary` cannot compile, because `Time` is a `struct`, and if you are returning a `new Time` in `opBinary`, you should return a `Time*`. Currently it's working because you are not using it. Finally, there is a module in druntime for time management, which provides a very nice API: `core.time : Duration`. It will allow you to do everything you want to do with your code, and more. For example: `import core.time; auto time = 1.hour; writeln(time);`
Sep 03 2022