Re: Can anyone provide an example of how D templates are overridable by global symbols?

2022-01-27 Thread kinke via Digitalmars-d-learn

An example:

a.d:
```
import core.stdc.stdio;

void foo()() {
version (Oops)
printf("  foo - oops\n");
else
printf("  foo\n");
}

void doA() {
printf("doA:\n");
foo!();
}
```

b.d:
```
import core.stdc.stdio;
import a;

void main() {
printf("main:\n");
foo!();
doA();
}
```

```bash
$ dmd -c a.d -version=Oops
$ dmd -c b.d
$ dmd a.o b.o -of=ab
$ ./ab
main:
  foo - oops
doA:
  foo - oops
$ dmd b.o a.o -of=ba
$ ./ba
main:
  foo
doA:
  foo
```

Each object file contains a foo!() instantiation (in a.o, the 
Oops version). No inlining, so the linker takes one of the weak 
definitions, and we end up with a consistent behavior for both 
calls - but the picked version is determined by the order of the 
object files.


Now if the calls are inlined, the behavior might not be 
consistent anymore. So separate compilations with different 
compiler flags can cause observable differences.


Re: gdc or ldc for faster programs?

2022-01-27 Thread Siarhei Siamashka via Digitalmars-d-learn

On Thursday, 27 January 2022 at 18:12:18 UTC, Johan Engelen wrote:
But the language requires ODR, so we can emit templates as 
weak_odr, telling the optimizer and linker that the symbols 
should be merged _and_ that ODR can be assumed to hold (i.e. 
inlining is OK).


Thanks! This was also my impression. But the problem is that Iain 
Buclaw seems to disagree with us. He claims that template 
functions must be overridable by global functions and this is 
supposed to inhibit template functions inlining. Is there any 
independent source to back up your or Iain's claim?


The onus of honouring ODR is on the user - not the compiler - 
because we allow the user to do separate compilation.


My own limited experiments with various code snippets convinced 
me that D compilers actually try their best to prevent ODR 
violation, so it isn't like users can easily hurt themselves: 
https://forum.dlang.org/thread/cstjhjvmmibonbajw...@forum.dlang.org


Also module names are added as a part of function names mangling. 
Having an accidental clash of symbol names shouldn't be very 
likely in a valid D project. Though I'm not absolutely sure 
whether this provides a sufficient safety net.


Re: Can anyone provide an example of how D templates are overridable by global symbols?

2022-01-27 Thread Siarhei Siamashka via Digitalmars-d-learn
On Thursday, 9 December 2021 at 21:06:54 UTC, Siarhei Siamashka 
wrote:
On Thursday, 9 December 2021 at 20:53:52 UTC, Siarhei Siamashka 
wrote:
  How would one construct a simple example of a template 
symbol getting successfully overridden by a global symbol?


Forgot to mention that a template function can be overridden by 
another function with the same name. But only as long as all of 
this happens in the scope of a single module. Here are a few 
examples (all of them successfully compile and run):


```D
import std.stdio;

T f(T)(T a, T b) { return a + b; }
int f(int a, int b) { return a - b; }

void main()
{
  f(2, 1).writeln; // prints "1"
}
```

```D
import std.stdio;

int f(int a, int b) { return a - b; }
T f(T)(T a, T b) { return a + b; }

void main()
{
  f(2, 1).writeln; // prints "1"
}
```

```D
import std.stdio;

import template_f;
int f(int a, int b) { return a - b; }

void main()
{
  f(2, 1).writeln; // prints "1"
}
```

```D
import std.stdio;

import nontemplate_f;
T f(T)(T a, T b) { return a + b; }

void main()
{
  f(2, 1).writeln; // prints "3"
}
```

This mostly agrees with the following part of the D language 
specification: https://dlang.org/spec/module.html#name_lookup


Except that having a template function and a non-template 
function with the same name within the same module scope doesn't 
seem to be explicitly documented in the D specification. But such 
name clash appears to be resolved in favor of a non-template 
function. And this behavior shouldn't inhibit functions inlining.


Re: Embarrassed to ask this question because it seems so trivial but genuinely curious...

2022-01-27 Thread H. S. Teoh via Digitalmars-d-learn
On Thu, Jan 27, 2022 at 05:42:09PM +, WhatMeWorry via Digitalmars-d-learn 
wrote:
> While studying Ali's book at chapter "Constructor and Other Special
> Functions" and the below code snippet:
[...]
> // Original
> //this(int i) const { writeln("a const object"); }
> //this(int i) immutable { writeln("an immutable object"); }
> //this(int i) shared { writeln("a shared object"); }
> 
> const this(int i) { writeln("a const object"); }
> immutable this(int i) { writeln("an immutable object"); }
> shared this(int i) { writeln("a shared object"); }
[...]
> Assuming I can speak in correct programmer-ese: I was wondering why
> the qualifiers were placed after the function parameter list (int i).
> Just for fun, I moved to type qualifiers before the function
> definitions "this" (like a return type?) and the output was  exactly
> identical.  So I guess my question is, is this just a matter of
> esthetics or is some more nuanced goal at work here?

In method declarations, modifiers like const/immutable/shared play two
distinct roles:

1) Qualifying the return type of the method;
2) Qualifying the implicit `this` parameter of the method.

Historically, D has been rather lax about where qualifiers in the sense
of (2) can go, so that's why:

const this()

is the same as

this() const

They both mean that the implicit `this` parameter (not to be confused
with `this` as the name of the ctor) is const.

Personally, though, I prefer the 2nd form, because the first form could
potentially be ambiguous in non-ctor member functions:

struct S {
const int method();
}

Does the const apply to `int` or to the implicit `this` parameter? It's
not obvious. Better to write it this way:

int method() const; // const applied to `this`
const(int) method();// const applied to return type

N.B. the parentheses in `const(int)` -- while D is lax in allowing you
to write `const int`, that leads to the ambiguous situation above. My
personal recommendation is to always parenthesize qualified types so
that they are never ambiguous.


T

-- 
Mediocrity has been pushed to extremes.


Re: gdc or ldc for faster programs?

2022-01-27 Thread Johan Engelen via Digitalmars-d-learn

On Thursday, 27 January 2022 at 16:46:59 UTC, Ali Çehreli wrote:


What I know is that weak symbols can be overridden by strong 
symbols during linking. Which means, if a function body is 
inlined which also has a weak symbol, some part of the program 
may be using the inlined definition and some other parts may be 
using the overridden definition. Thanks to separate 
compilation, they need not match hence the violation of the 
one-definition rule (ODR).


But the language requires ODR, so we can emit templates as 
weak_odr, telling the optimizer and linker that the symbols 
should be merged _and_ that ODR can be assumed to hold (i.e. 
inlining is OK).
The onus of honouring ODR is on the user - not the compiler - 
because we allow the user to do separate compilation. Some more 
detailed explanation and example:

https://stackoverflow.com/questions/44335046/how-does-the-linker-handle-identical-template-instantiations-across-translation/44346057

-Johan



Re: Embarrassed to ask this question because it seems so trivial but genuinely curious...

2022-01-27 Thread Steven Schveighoffer via Digitalmars-d-learn

On 1/27/22 12:42 PM, WhatMeWorry wrote:

Assuming I can speak in correct programmer-ese: I was wondering why the 
qualifiers were placed after the function parameter list (int i).  Just 
for fun, I moved to type qualifiers before the function definitions 
"this" (like a return type?) and the output was  exactly identical.  So 
I guess my question is, is this just a matter of esthetics or is some 
more nuanced goal at work here?


For constructors, being on the front is not misleading. But for a member 
function that returns a value, take a look:


```d
struct S
{
   int * x;
   const int *foo() { return x; }
}
```

What do you think happens here?

The answer, is that this is a compiler error. The error is that the 
`const` applies to the `this` parameter and *not* the return value. So 
you are accepting a `const S`, and trying to return its member `x` as a 
plain `int *`.


This is why we always recommend putting the `this` modifiers at the end 
of the function to make it visually clear that they don't apply to the 
return value.


-Steve


Re: Embarrassed to ask this question because it seems so trivial but genuinely curious...

2022-01-27 Thread Dennis via Digitalmars-d-learn

On Thursday, 27 January 2022 at 17:42:09 UTC, WhatMeWorry wrote:
So I guess my question is, is this just a matter of esthetics 
or is some more nuanced goal at work here?


It doesn't matter much for constructors, but in general, the 
problem with placing qualifiers in front is that it looks 
confusing:

```D
struct S
{
immutable int[] f()
{
return [];
}
}
```

This reads as if it returns an `immutable(int[])`, but it 
doesn't, the `immutable` means that it can only be called on 
`immutable` instances of `S`.





Embarrassed to ask this question because it seems so trivial but genuinely curious...

2022-01-27 Thread WhatMeWorry via Digitalmars-d-learn
While studying Ali's book at chapter "Constructor and Other 
Special Functions" and the below code snippet:



import std.stdio;

struct S {
this(int i) { writeln("an object"); }

// Original
//this(int i) const { writeln("a const object"); }
//this(int i) immutable { writeln("an immutable object"); 
}

//this(int i) shared { writeln("a shared object"); }

const this(int i) { writeln("a const object"); }
immutable this(int i) { writeln("an immutable object"); }
shared this(int i) { writeln("a shared object"); }
}

void main() {
auto m = S(1);
auto c = const(S)(2);
auto i = immutable(S)(3);
auto s = shared(S)(4);
}

Assuming I can speak in correct programmer-ese: I was wondering 
why the qualifiers were placed after the function parameter list 
(int i).  Just for fun, I moved to type qualifiers before the 
function definitions "this" (like a return type?) and the output 
was  exactly identical.  So I guess my question is, is this just 
a matter of esthetics or is some more nuanced goal at work here?






Re: gdc or ldc for faster programs?

2022-01-27 Thread H. S. Teoh via Digitalmars-d-learn
On Thu, Jan 27, 2022 at 08:46:59AM -0800, Ali Çehreli via Digitalmars-d-learn 
wrote:
[...]
> I see that template instantiations are linked through weak symbols:
> 
> $ nm deneme | grep foo
> [...]
> 00021380 W _D6deneme__T3fooTiZQhFNaNbNiNfZv
> 
> What I know is that weak symbols can be overridden by strong symbols
> during linking.
[...]

Yes, and it also means that only one copy of the symbol will make it
into the executable. This is one of the ways we leverage the linker to
eliminate (merge) duplicate template instantiations.


T

-- 
Claiming that your operating system is the best in the world because more 
people use it is like saying McDonalds makes the best food in the world. -- 
Carl B. Constantine


Re: gdc or ldc for faster programs?

2022-01-27 Thread Ali Çehreli via Digitalmars-d-learn

On 1/26/22 11:07, Siarhei Siamashka wrote:
> On Wednesday, 26 January 2022 at 18:41:51 UTC, Iain Buclaw wrote:
>> The D language shot itself in the foot by requiring templates to have
>> weak semantics.
>>
>> If DMD and LDC inline weak functions, that's their bug.
>
> As I already mentioned in the bugzilla, it would be really useful to see
> a practical example of DMD and LDC running into troubles because of
> mishandling weak templates.

I am not experienced enough to answer but the way I understand weak 
symbols, it is possible to run into trouble but it will probably never 
happen. When it happens, I suspect people can find workarounds like 
disabling inlining.


> I was never able to find anything about
> "requiring templates to have weak semantics" anywhere in the Dlang
> documentation or on the Internet.

The truth is some part of D's spec is the implementation. When I compile 
the following program (with dmd)


void foo(T)() {}

void main() {
  foo!int();
}

I see that template instantiations are linked through weak symbols:

$ nm deneme | grep foo
[...]
00021380 W _D6deneme__T3fooTiZQhFNaNbNiNfZv

What I know is that weak symbols can be overridden by strong symbols 
during linking. Which means, if a function body is inlined which also 
has a weak symbol, some part of the program may be using the inlined 
definition and some other parts may be using the overridden definition. 
Thanks to separate compilation, they need not match hence the violation 
of the one-definition rule (ODR).


Ali



Re: Template sequence parameter and default value

2022-01-27 Thread Ali Çehreli via Digitalmars-d-learn

On 1/26/22 18:49, Andrey Zherikov wrote:

> I want something like this:
> ```d
> void foo(MODULES... = __MODULE__)() {}

Two other options:

1)

void foo(MODULES_...)() {
  static if (MODULES_.length == 0) {
import std.meta : AliasSeq;
alias MODULES = AliasSeq!__MODULE__;

  } else {
alias MODULES = MODULES_;
  }
}

2)

void foo(MODULES_...)() {
}

void foo() {
  return foo!__MODULE__;
}

Ali



Re: Template sequence parameter and default value

2022-01-27 Thread Steven Schveighoffer via Digitalmars-d-learn

On 1/27/22 10:21 AM, Andrey Zherikov wrote:


So is it possible to get rid of the alias?


I'm not sure it's worth the effort? Yours is a pretty straightforward 
solution.


-Steve


Re: Template sequence parameter and default value

2022-01-27 Thread Andrey Zherikov via Digitalmars-d-learn

On Thursday, 27 January 2022 at 03:19:59 UTC, Jaime wrote:
You can accomplish this by heading off the template sequence 
parameter with several default template parameters. If you need 
them all under one name, you can recombine them in the function 
body with std.meta.AliasSeq, the effective "kind" of a template 
sequence parameter.


Example:

```d
void foo(string FirstModule = __MODULE__, RestModules...)() {
alias Modules = AliasSeq!(FirstModule, RestModules);
// things
}

// foo!(module1, module2) => alias Modules = (module1, module2)
// foo!() => alias Modules = (__MODULE__)
```


Unfortunately `string FirstModule` doesn't work if I specify the 
module: https://run.dlang.io/is/BZd0KB


The closest solution I have is this:
```d
void foo(MODULES...)()
{
writeln(MODULES.stringof);
}
alias foo(string MODULE = __MODULE__) = foo!(mixin(MODULE));

void main()
{
writeln(1);
foo();
writeln(2);
foo!(onlineapp);
writeln(3);
foo!(onlineapp,onlineapp);
}
```

It prints this:
```
1
tuple(module onlineapp)
2
tuple(module onlineapp)
3
tuple(module onlineapp, module onlineapp)
```

So is it possible to get rid of the alias?


Re: Order of object fields

2022-01-27 Thread Steven Schveighoffer via Digitalmars-d-learn

On 1/27/22 8:13 AM, Steven Schveighoffer wrote:

On Thursday, 27 January 2022 at 12:45:20 UTC, frame wrote:
Is the order of fields guaranteed returned by `.tupleof` and 
`__traits(getMember,...)`, can I rely on this? I know that are 
different things, I mean just per each use case if I have more 
functions that traverses through all fields. Thx.


Not for classes. The compiler is free to reorder if it wants to.

Yes for structs.


To clarify, the compiler can reorder the members to fit them better. But 
it will be the same order for any particular build of the object files.


Any compile-time features that fetch the members should be in the same 
order as the compiler has decided to lay them out. It's just that it 
might not match the source code order.


-Steve


Re: Order of object fields

2022-01-27 Thread Steven Schveighoffer via Digitalmars-d-learn

On Thursday, 27 January 2022 at 12:45:20 UTC, frame wrote:
Is the order of fields guaranteed returned by `.tupleof` and 
`__traits(getMember,...)`, can I rely on this? I know that are 
different things, I mean just per each use case if I have more 
functions that traverses through all fields. Thx.


Not for classes. The compiler is free to reorder if it wants to.

Yes for structs.

-Steve


Order of object fields

2022-01-27 Thread frame via Digitalmars-d-learn
Is the order of fields guaranteed returned by `.tupleof` and 
`__traits(getMember,...)`, can I rely on this? I know that are 
different things, I mean just per each use case if I have more 
functions that traverses through all fields. Thx.