www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - using .init reliably

reply Cauterite <cauterite gmail.com> writes:
How can I get the initial value of an arbitrary type? Since any 
struct can override it, .init is not reliable:

struct Z {
	enum init = 6;
	string val = `asdf`;
};
assert(Z.init == 6);
assert(typeof(Z()).init == 6);

I know I could use
*(cast(Z*) typeid(Z).initializer.ptr)
but that doesn't work in CTFE (because the typeinfo doesn't exist 
yet).

Z() is obviously not reliable either since it can override static 
opCall.
Aug 26 2016
parent reply Jonathan M Davis via Digitalmars-d-learn writes:
On Friday, August 26, 2016 08:59:55 Cauterite via Digitalmars-d-learn wrote:
 How can I get the initial value of an arbitrary type? Since any
 struct can override it, .init is not reliable:

 struct Z {
   enum init = 6;
   string val = `asdf`;
 };
 assert(Z.init == 6);
 assert(typeof(Z()).init == 6);

 I know I could use
 *(cast(Z*) typeid(Z).initializer.ptr)
 but that doesn't work in CTFE (because the typeinfo doesn't exist
 yet).

 Z() is obviously not reliable either since it can override static
 opCall.
Nothing should ever override init. If it does, then it should be fixed so that it doesn't. It was an oversight that it was ever allowed, and I believe that there's a bug report for it. You're supposed to be able to depend on .init existing. Default initialization for structs can be disabled via disable this(); but even then, the init member still exists (it just isn't used for default initialization). All types have an init property, and it's critical that that be the case. There's a lot of code (including in druntime and Phobos) which relies on that fact. So, just use .init, and if a type incorrectly defines init, then it's just not going not play nicely, and it needs to be fixed. And I expect that it will become an error at some point in the future to define an init member for a user-defined type, at which point, there won't be any choice about fixing it. - Jonathan M Davis
Aug 26 2016
next sibling parent reply Cauterite <cauterite gmail.com> writes:
On Friday, 26 August 2016 at 09:48:00 UTC, Jonathan M Davis wrote:
 And I expect that it will become an error at some point in the 
 future to define an init member for a user-defined type, at 
 which point, there won't be any choice about fixing it.
I might take a crack at this patch. Sounds pretty trivial.
Aug 26 2016
next sibling parent Jonathan M Davis via Digitalmars-d-learn writes:
On Friday, August 26, 2016 10:52:47 Cauterite via Digitalmars-d-learn wrote:
 On Friday, 26 August 2016 at 09:48:00 UTC, Jonathan M Davis wrote:
 And I expect that it will become an error at some point in the
 future to define an init member for a user-defined type, at
 which point, there won't be any choice about fixing it.
I might take a crack at this patch. Sounds pretty trivial.
The key thing to keep in mind is that it needs to be deprecated first rather than just simply made an error (in order to avoid breaking existing code without warning), which may or may not make it more complicated. I'm not familiar with much of the compiler's internals. Regardless, it would be great if we could move towards making it illegal to define init for a type, since it's a definitely problem that it's been possible. - Jonathan M Davis
Aug 26 2016
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 8/26/16 6:52 AM, Cauterite wrote:
 On Friday, 26 August 2016 at 09:48:00 UTC, Jonathan M Davis wrote:
 And I expect that it will become an error at some point in the future
 to define an init member for a user-defined type, at which point,
 there won't be any choice about fixing it.
I might take a crack at this patch. Sounds pretty trivial.
FYI, you cannot make this patch until we fully deprecate the use of TypeInfo.init: https://github.com/dlang/druntime/blob/master/src/object.d#L294 So at least until 2.075. -Steve
Aug 26 2016
parent reply Cauterite <cauterite gmail.com> writes:
On Friday, 26 August 2016 at 15:14:42 UTC, Steven Schveighoffer 
wrote:
 FYI, you cannot make this patch until we fully deprecate the 
 use of TypeInfo.init: 
 https://github.com/dlang/druntime/blob/master/src/object.d#L294

 So at least until 2.075.

 -Steve
Ah yes, good thinking. I'll keep that in mind.
Aug 26 2016
parent reply Alex <sascha.orlov gmail.com> writes:
Sorry for dig out this posting, but this one is more recent, than

http://forum.dlang.org/thread/k15of5$22ub$1 digitalmars.com?page=1

and my question is just beyond the two:

I'm with you, regarding that the standard init property should 
not be overridden. But how about to override it with a custom 
init function, which has a different interface?

An example:

/// --- code --- ///
void main()
{
	int first = 5;
	//auto s0 = S.init; // this line (4) yields an error:
         // function app.S.init (int fParam) is not callable using 
argument types ()
	S.init(first);
	int second = 2;
	auto s = S(second);
	assert(s.first == first);
	assert(s.second == second);
}

struct S
{
	static int first;
	int second;

	// I'm aware of the fact, that nobody should redefine init() 
like:
	// static auto init() { writeln("oh-oh..."); }

	static void init(int fParam) { first = fParam; }

	this(int sParam) { second = sParam; }
}
/// --- code --- ///

My question has some components:

1. If this also should be disallowed: why, as it could be 
possible, that I'm not aware of existence of any init property of 
every struct.

2. Regardless of the result of the first question, line 4 of the 
example yields an error, although I didn't touch the standard 
init property. Why?

3. A practical aspect: What I try to solve is a two-stage 
initialization of an object. I know, this should be avoided. In 
order to do this, I try to separate the initializations of the 
type and its objects.
(By the way, is this the right way to go?)

Of course, I could use an external function, say
prepareType(S)(int fParam)
to do so, and this is the place, where I remembered the old 
posting and found the current one.

As we are already beyond 2.075, are there known tickets about the 
disabling of the ability to override the init property, where I 
can post the bug of the second question, in case it is one?

4. The chipped in question in the previous paragraph :)
Oct 30 2017
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 10/30/17 6:59 AM, Alex wrote:
 Sorry for dig out this posting, but this one is more recent, than
 
 http://forum.dlang.org/thread/k15of5$22ub$1 digitalmars.com?page=1
 
 and my question is just beyond the two:
 
 I'm with you, regarding that the standard init property should not be 
 overridden. But how about to override it with a custom init function, 
 which has a different interface?
 
 An example:
 
 /// --- code --- ///
 void main()
 {
      int first = 5;
      //auto s0 = S.init; // this line (4) yields an error:
          // function app.S.init (int fParam) is not callable using 
 argument types ()
      S.init(first);
      int second = 2;
      auto s = S(second);
      assert(s.first == first);
      assert(s.second == second);
 }
 
 struct S
 {
      static int first;
      int second;
 
      // I'm aware of the fact, that nobody should redefine init() like:
      // static auto init() { writeln("oh-oh..."); }
 
      static void init(int fParam) { first = fParam; }
This should also be disallowed. In order to know x.init means what it normally means, we shouldn't allow overriding it. This is the point of this thread, and the impetus for renaming of TypeInfo.init().
 
      this(int sParam) { second = sParam; }
 }
 /// --- code --- ///
 
 My question has some components:
 
 1. If this also should be disallowed: why, as it could be possible, that 
 I'm not aware of existence of any init property of every struct.
The .init property is provided by the compiler, unless you define it. It means the default value of the type.
 2. Regardless of the result of the first question, line 4 of the example 
 yields an error, although I didn't touch the standard init property. Why?
Once you override the property, the compiler will always use that. You can't override a name and then have it fall back on the default name for a different overload. D is very careful to resolve symbol names in an unambiguous way.
 3. A practical aspect: What I try to solve is a two-stage initialization 
 of an object. I know, this should be avoided. In order to do this, I try 
 to separate the initializations of the type and its objects.
 (By the way, is this the right way to go?)
What you can do is simply rename the static method. Certainly a valid route to have a method to initialize the type variables. Note that the way you have it, 'first' is a thread-local variable, so it would have to be initialized in every thread.
 Of course, I could use an external function, say
 prepareType(S)(int fParam)
 to do so, and this is the place, where I remembered the old posting and 
 found the current one.
Whether you put it inside the type or not is a preference. Either way is fine. It just shouldn't be named init if it's a member.
 As we are already beyond 2.075, are there known tickets about the 
 disabling of the ability to override the init property, where I can post 
 the bug of the second question, in case it is one?
Clearly, we have dropped the ball on deprecating this. Not sure if there is a ticket on it. I'll make one for the time being. We should try deprecating it by 2.078 (overriding init that is). -Steve
Oct 30 2017
parent reply Alex <sascha.orlov gmail.com> writes:
On Monday, 30 October 2017 at 15:03:25 UTC, Steven Schveighoffer 
wrote:
 This should also be disallowed. In order to know x.init means 
 what it normally means, we shouldn't allow overriding it. This 
 is the point of this thread, and the impetus for renaming of 
 TypeInfo.init().
Yeah... my problem is, that I don't know it at compile time.
 The .init property is provided by the compiler, unless you 
 define it. It means the default value of the type.
I had something different in mind: Either the "init" property belongs to the semantic of a type (in this case a struct) or it doesn't. If it does (I think, this is the case at this time point), then it should be overloadable. However, restrictions can be applied, like "one cannot override the standard (i. e. empty) provided interface". If it does not, then, an overload, like I did should not be handled differently like every other overload, and the exception in my example would be a bug.
 2. Regardless of the result of the first question, line 4 of 
 the example yields an error, although I didn't touch the 
 standard init property. Why?
Once you override the property, the compiler will always use that. You can't override a name and then have it fall back on the default name for a different overload. D is very careful to resolve symbol names in an unambiguous way.
Ok, I'm sorry for the confusion :) My question was: While I'm agreeing, that the init property should not be overridden, could it be overloaded (with another interface)? And why if not? As different interfaces fully disambiguate names...
 3. A practical aspect: What I try to solve is a two-stage 
 initialization of an object. I know, this should be avoided. 
 In order to do this, I try to separate the initializations of 
 the type and its objects.
 (By the way, is this the right way to go?)
What you can do is simply rename the static method. Certainly a valid route to have a method to initialize the type variables.
So, using another interface is not the same, as using another name? Or is the init property handled differently? ;)
 Note that the way you have it, 'first' is a thread-local 
 variable, so it would have to be initialized in every thread.
Yes, this is the intention. Thanks a lot :) Alex
Oct 30 2017
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 10/30/17 11:39 AM, Alex wrote:
 On Monday, 30 October 2017 at 15:03:25 UTC, Steven Schveighoffer wrote:
 This should also be disallowed. In order to know x.init means what it 
 normally means, we shouldn't allow overriding it. This is the point of 
 this thread, and the impetus for renaming of TypeInfo.init().
Yeah... my problem is, that I don't know it at compile time.
You know it at language time :)
 The .init property is provided by the compiler, unless you define it. 
 It means the default value of the type.
I had something different in mind: Either the "init" property belongs to the semantic of a type (in this case a struct) or it doesn't.
It belongs to the language. The init property should be only allowed by the language. It doesn't need to be a keyword, but it should not be allowed as a member function or field.
 If it does (I think, this is the case at this time point), then it 
 should be overloadable. However, restrictions can be applied, like "one 
 cannot override the standard (i. e. empty) provided interface".
 If it does not, then, an overload, like I did should not be handled 
 differently like every other overload, and the exception in my example 
 would be a bug.
It should not be overridable. Otherwise, we cannot reason about low-level concepts that build types from scratch.
 Once you override the property, the compiler will always use that. You 
 can't override a name and then have it fall back on the default name 
 for a different overload. D is very careful to resolve symbol names in 
 an unambiguous way.
Ok, I'm sorry for the confusion :) My question was: While I'm agreeing, that the init property should not be overridden, could it be overloaded (with another interface)? And why if not? As different interfaces fully disambiguate names...
No, it shouldn't be overridden. Why not? Because so much generic code assumes that T.init or t.init (instance t of type T) means "the compile-time defined initializer for type T", and to allow any overriding of this would be hugely damaging to such functions. Yes, I understand that you want to not override the getter init property, but simply choose another name for your function, and it should work just fine. I recommend "initializer" or "initialize" or "make".
 What you can do is simply rename the static method. Certainly a valid 
 route to have a method to initialize the type variables.
So, using another interface is not the same, as using another name? Or is the init property handled differently? ;)
In D, when you have overloads at different levels of priority, it doesn't matter. Whatever has the highest priority owns all the overloads. For instance: struct S { void foo(int x) {...} } void foo(S s, string x) {...} void main() { S s; s.foo("hi"); // error } My contention is that the language definition of init should have the highest priority. FYI: https://issues.dlang.org/show_bug.cgi?id=17954 -Steve
Oct 30 2017
parent Alex <sascha.orlov gmail.com> writes:
On Tuesday, 31 October 2017 at 02:24:48 UTC, Steven Schveighoffer 
wrote:
 Yeah... my problem is, that I don't know it at compile time.
You know it at language time :)
:)
 The .init property is provided by the compiler, unless you 
 define it. It means the default value of the type.
Here, I'm totally with you.
 It belongs to the language. The init property should be only 
 allowed by the language. It doesn't need to be a keyword, but 
 it should not be allowed as a member function or field.
Take for example, the sizeof property. It can't be redefined. Should be the init property of the same kind? Should it be not redefinable at all, or only to guarantee, to get a valid value? And if the latter, does it matter whether it as evaluable at compile time? If the former - I have no problem with this, it is just a possibility to init an object in special cases.
 In D, when you have overloads at different levels of priority, 
 it doesn't matter. Whatever has the highest priority owns all 
 the overloads.

 For instance:

 struct S
 {
    void foo(int x) {...}
 }

 void foo(S s, string x) {...}

 void main()
 {
    S s;
    s.foo("hi"); // error
 }
Ok, I was not aware of this... And this quiet my mind a lot :)
 My contention is that the language definition of init should 
 have the highest priority.

 FYI: https://issues.dlang.org/show_bug.cgi?id=17954
Ok, cool. Thanks for that, and think, the first comment by Jakob goes in the same direction, as I'm thinking of. So, my current problem is solved by your code sample and the different levels of priority hint. Thanks a a lot :)
Oct 31 2017
prev sibling parent reply Johan Engelen <j j.nl> writes:
On Friday, 26 August 2016 at 09:48:00 UTC, Jonathan M Davis wrote:
 
 You're supposed to be able to depend on .init existing. Default 
 initialization for structs can be disabled via

  disable this();

 but even then, the init member still exists (it just isn't used 
 for default initialization).
From what I remember, the last time I looked at ` disable this();`: it prevents the user from creating a default initialized struct. However whenever (compiler internally) the struct needs initialization, `.init` is still used. And thus it is also used at the start of any constructor the user writes. Don't take my word for it: have a look at asm output, or easier: LCD's LLVM IR output. -Johan
Aug 26 2016
parent Jonathan M Davis via Digitalmars-d-learn writes:
On Friday, August 26, 2016 11:20:56 Johan Engelen via Digitalmars-d-learn 
wrote:
 On Friday, 26 August 2016 at 09:48:00 UTC, Jonathan M Davis wrote:
 You're supposed to be able to depend on .init existing. Default
 initialization for structs can be disabled via

  disable this();

 but even then, the init member still exists (it just isn't used
 for default initialization).
From what I remember, the last time I looked at ` disable this();`: it prevents the user from creating a default initialized struct. However whenever (compiler internally) the struct needs initialization, `.init` is still used. And thus it is also used at the start of any constructor the user writes. Don't take my word for it: have a look at asm output, or easier: LCD's LLVM IR output.
I expect that that's true. The key thing is that if that if default initialization is disabled, then you can't do something like MyType mt; But init itself is pretty integral to the language, so it's still needed for other stuff. And it would be downright brutal if you couldn't depend on init to exist for metaprogramming - which is what the OP was afraid of. - Jonathan M Davis
Aug 26 2016