www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - We need something like source_location in D

reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
 From C++20: 
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1208r5.pdf

Instead of having to constantly declare "file = __FILE__, line = 
__LINE__" everywhere, it would be so much more useful to just 
have a single built-in type which we can default initialize . For 
example:

-----
import std.algorithm;

void checkAndThrow (lazy bool expression, Loc loc = __LOCATION__)
{
     if (!expression)
         throw new Exception("Failed", loc.file, loc.line);
}

void main ()
{
     auto arr = [1, 1, 1, 1];
     checkAndThrow(arr.sum == 4);

     // should throw with file+line of this statement
     checkAndThrow(arr.sum == 5);
}
-----

This also makes it very easy to extend in the future, because we 
don't have to pollute the namespace with a lot of "__"-style 
symbols.

The actual naming of the location symbol is something we can 
bikeshed over, that's fine.

If you grep for `string file = __FILE__, size_t line = __LINE__` 
or `string file = __FILE__, int line = __LINE__`, it is 
everywhere in Druntime and Phobos. I think it's time we got rid 
of this repetition.

I know __traits(getLocation) got implemented recently, but it's 
not very useful in this context because it returns a tuple 
(https://github.com/dlang/dmd/pull/10013). I don't see an easy 
way to use it in function parameters.

Should I write a DIP for this?
Jul 30
next sibling parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Wednesday, 31 July 2019 at 01:39:05 UTC, Andrej Mitrovic wrote:
 From C++20: 
 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1208r5.pdf

 Instead of having to constantly declare "file = __FILE__, line 
 = __LINE__" everywhere, it would be so much more useful to just 
 have a single built-in type which we can default initialize . 
 For example:

 -----
 import std.algorithm;

 void checkAndThrow (lazy bool expression, Loc loc = 
 __LOCATION__)
 {
     if (!expression)
         throw new Exception("Failed", loc.file, loc.line);
 }

 void main ()
 {
     auto arr = [1, 1, 1, 1];
     checkAndThrow(arr.sum == 4);

     // should throw with file+line of this statement
     checkAndThrow(arr.sum == 5);
 }
 -----

 This also makes it very easy to extend in the future, because 
 we don't have to pollute the namespace with a lot of "__"-style 
 symbols.

 The actual naming of the location symbol is something we can 
 bikeshed over, that's fine.

 If you grep for `string file = __FILE__, size_t line = 
 __LINE__` or `string file = __FILE__, int line = __LINE__`, it 
 is everywhere in Druntime and Phobos. I think it's time we got 
 rid of this repetition.

 I know __traits(getLocation) got implemented recently, but it's 
 not very useful in this context because it returns a tuple 
 (https://github.com/dlang/dmd/pull/10013). I don't see an easy 
 way to use it in function parameters.
It returning a tuple is not the problem because they auto expand : void foo(string a, int b, int c) { import std.stdio; writeln(a, " ", b); } void main() { foo(__traits(getLocation,foo)); } That you can't pass the caller loc is. A DIP will take a long time, I don't think the addition of __SYMBOLS__ require one. The addition of a type will possibly be problematic, but if `Loc` were a tuple that would be fine if we could do void foo(auto a = 1); since it would be just as silly to have to type void foo(typeof(__LOCATION__) loc = __LOCATION__);
Jul 30
next sibling parent FeepingCreature <feepingcreature gmail.com> writes:
On Wednesday, 31 July 2019 at 03:54:13 UTC, Nicholas Wilson wrote:
 On Wednesday, 31 July 2019 at 01:39:05 UTC, Andrej Mitrovic
 I know __traits(getLocation) got implemented recently, but 
 it's not very useful in this context because it returns a 
 tuple (https://github.com/dlang/dmd/pull/10013). I don't see 
 an easy way to use it in function parameters.
It returning a tuple is not the problem because they auto expand :
Making it a struct would be beneficial for another reason: the two members of the tuple are string and int. Since we're abusing default parameters here, note that those are both really common types that are very easy to pass accidentally. A dedicated data type avoids this issue.
Jul 30
prev sibling next sibling parent Manu <turkeyman gmail.com> writes:
On Tue, Jul 30, 2019 at 8:55 PM Nicholas Wilson via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On Wednesday, 31 July 2019 at 01:39:05 UTC, Andrej Mitrovic wrote:
 From C++20:
 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1208r5.pdf

 Instead of having to constantly declare "file = __FILE__, line
 = __LINE__" everywhere, it would be so much more useful to just
 have a single built-in type which we can default initialize .
 For example:

 -----
 import std.algorithm;

 void checkAndThrow (lazy bool expression, Loc loc =
 __LOCATION__)
 {
     if (!expression)
         throw new Exception("Failed", loc.file, loc.line);
 }

 void main ()
 {
     auto arr = [1, 1, 1, 1];
     checkAndThrow(arr.sum == 4);

     // should throw with file+line of this statement
     checkAndThrow(arr.sum == 5);
 }
 -----

 This also makes it very easy to extend in the future, because
 we don't have to pollute the namespace with a lot of "__"-style
 symbols.

 The actual naming of the location symbol is something we can
 bikeshed over, that's fine.

 If you grep for `string file = __FILE__, size_t line =
 __LINE__` or `string file = __FILE__, int line = __LINE__`, it
 is everywhere in Druntime and Phobos. I think it's time we got
 rid of this repetition.

 I know __traits(getLocation) got implemented recently, but it's
 not very useful in this context because it returns a tuple
 (https://github.com/dlang/dmd/pull/10013). I don't see an easy
 way to use it in function parameters.
It returning a tuple is not the problem because they auto expand : void foo(string a, int b, int c) { import std.stdio; writeln(a, " ", b); } void main() { foo(__traits(getLocation,foo)); } That you can't pass the caller loc is. A DIP will take a long time, I don't think the addition of __SYMBOLS__ require one. The addition of a type will possibly be problematic, but if `Loc` were a tuple that would be fine if we could do void foo(auto a = 1); since it would be just as silly to have to type void foo(typeof(__LOCATION__) loc = __LOCATION__);
Make a `Loc` type in the library: struct Loc { string file; int line; int column; } Make a helper to construct one: template getLoc(alias symbol) { enum getLoc = return Loc(__traits(getLocation, symbol)); } Do: Loc loc = getLoc!mySymbol; Trivial.
Jul 30
prev sibling next sibling parent Manu <turkeyman gmail.com> writes:
On Tue, Jul 30, 2019 at 11:29 PM Manu <turkeyman gmail.com> wrote:
 On Tue, Jul 30, 2019 at 8:55 PM Nicholas Wilson via Digitalmars-d
 <digitalmars-d puremagic.com> wrote:
 On Wednesday, 31 July 2019 at 01:39:05 UTC, Andrej Mitrovic wrote:
 From C++20:
 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1208r5.pdf

 Instead of having to constantly declare "file = __FILE__, line
 = __LINE__" everywhere, it would be so much more useful to just
 have a single built-in type which we can default initialize .
 For example:

 -----
 import std.algorithm;

 void checkAndThrow (lazy bool expression, Loc loc =
 __LOCATION__)
 {
     if (!expression)
         throw new Exception("Failed", loc.file, loc.line);
 }

 void main ()
 {
     auto arr = [1, 1, 1, 1];
     checkAndThrow(arr.sum == 4);

     // should throw with file+line of this statement
     checkAndThrow(arr.sum == 5);
 }
 -----

 This also makes it very easy to extend in the future, because
 we don't have to pollute the namespace with a lot of "__"-style
 symbols.

 The actual naming of the location symbol is something we can
 bikeshed over, that's fine.

 If you grep for `string file = __FILE__, size_t line =
 __LINE__` or `string file = __FILE__, int line = __LINE__`, it
 is everywhere in Druntime and Phobos. I think it's time we got
 rid of this repetition.

 I know __traits(getLocation) got implemented recently, but it's
 not very useful in this context because it returns a tuple
 (https://github.com/dlang/dmd/pull/10013). I don't see an easy
 way to use it in function parameters.
It returning a tuple is not the problem because they auto expand : void foo(string a, int b, int c) { import std.stdio; writeln(a, " ", b); } void main() { foo(__traits(getLocation,foo)); } That you can't pass the caller loc is. A DIP will take a long time, I don't think the addition of __SYMBOLS__ require one. The addition of a type will possibly be problematic, but if `Loc` were a tuple that would be fine if we could do void foo(auto a = 1); since it would be just as silly to have to type void foo(typeof(__LOCATION__) loc = __LOCATION__);
Make a `Loc` type in the library: struct Loc { string file; int line; int column; } Make a helper to construct one: template getLoc(alias symbol) { enum getLoc = return Loc(__traits(getLocation, symbol)); }
I refactored my original idea and left it broken... it should be this: enum getLoc = Loc(__traits(getLocation, symbol));
Jul 30
prev sibling parent reply Manu <turkeyman gmail.com> writes:
On Tue, Jul 30, 2019 at 11:31 PM Manu <turkeyman gmail.com> wrote:
 On Tue, Jul 30, 2019 at 11:29 PM Manu <turkeyman gmail.com> wrote:
 On Tue, Jul 30, 2019 at 8:55 PM Nicholas Wilson via Digitalmars-d
 <digitalmars-d puremagic.com> wrote:
 On Wednesday, 31 July 2019 at 01:39:05 UTC, Andrej Mitrovic wrote:
 From C++20:
 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1208r5.pdf

 Instead of having to constantly declare "file = __FILE__, line
 = __LINE__" everywhere, it would be so much more useful to just
 have a single built-in type which we can default initialize .
 For example:

 -----
 import std.algorithm;

 void checkAndThrow (lazy bool expression, Loc loc =
 __LOCATION__)
 {
     if (!expression)
         throw new Exception("Failed", loc.file, loc.line);
 }

 void main ()
 {
     auto arr = [1, 1, 1, 1];
     checkAndThrow(arr.sum == 4);

     // should throw with file+line of this statement
     checkAndThrow(arr.sum == 5);
 }
 -----

 This also makes it very easy to extend in the future, because
 we don't have to pollute the namespace with a lot of "__"-style
 symbols.

 The actual naming of the location symbol is something we can
 bikeshed over, that's fine.

 If you grep for `string file = __FILE__, size_t line =
 __LINE__` or `string file = __FILE__, int line = __LINE__`, it
 is everywhere in Druntime and Phobos. I think it's time we got
 rid of this repetition.

 I know __traits(getLocation) got implemented recently, but it's
 not very useful in this context because it returns a tuple
 (https://github.com/dlang/dmd/pull/10013). I don't see an easy
 way to use it in function parameters.
It returning a tuple is not the problem because they auto expand : void foo(string a, int b, int c) { import std.stdio; writeln(a, " ", b); } void main() { foo(__traits(getLocation,foo)); } That you can't pass the caller loc is. A DIP will take a long time, I don't think the addition of __SYMBOLS__ require one. The addition of a type will possibly be problematic, but if `Loc` were a tuple that would be fine if we could do void foo(auto a = 1); since it would be just as silly to have to type void foo(typeof(__LOCATION__) loc = __LOCATION__);
Make a `Loc` type in the library: struct Loc { string file; int line; int column; } Make a helper to construct one: template getLoc(alias symbol) { enum getLoc = return Loc(__traits(getLocation, symbol)); }
I refactored my original idea and left it broken... it should be this: enum getLoc = Loc(__traits(getLocation, symbol));
3rd time's the charm! enum getLoc(alias symbol) = Loc(__traits(getLocation, symbol));
Jul 30
parent guy hebert <guyhebert143 outlook.com> writes:
On Wednesday, 31 July 2019 at 06:31:40 UTC, Manu wrote:
 On Tue, Jul 30, 2019 at 11:31 PM Manu <turkeyman gmail.com> 
 wrote:
 On Tue, Jul 30, 2019 at 11:29 PM Manu <turkeyman gmail.com> 
 wrote:
 On Tue, Jul 30, 2019 at 8:55 PM Nicholas Wilson via 
 Digitalmars-d <digitalmars-d puremagic.com> wrote:
 On Wednesday, 31 July 2019 at 01:39:05 UTC, Andrej 
 Mitrovic wrote:
 From C++20: 
 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1208r5.pdf

 Instead of having to constantly declare "file = 
 __FILE__, line = __LINE__" everywhere, it would be so 
 much more useful to just have a single built-in type 
 which we can default initialize . For example:

 -----
 import std.algorithm;

 void checkAndThrow (lazy bool expression, Loc loc =
 __LOCATION__)
 {
     if (!expression)
         throw new Exception("Failed", loc.file, 
 loc.line);
 }

 void main ()
 {
     auto arr = [1, 1, 1, 1];
     checkAndThrow(arr.sum == 4);

     // should throw with file+line of this statement
     checkAndThrow(arr.sum == 5);
 }
 -----

 This also makes it very easy to extend in the future, 
 because we don't have to pollute the namespace with a 
 lot of "__"-style symbols.

 The actual naming of the location symbol is something we 
 can bikeshed over, that's fine.

 If you grep for `string file = __FILE__, size_t line = 
 __LINE__` or `string file = __FILE__, int line = 
 __LINE__`, it is everywhere in Druntime and Phobos. I 
 think it's time we got rid of this repetition.

 I know __traits(getLocation) got implemented recently, 
 but it's not very useful in this context because it 
 returns a tuple 
 (https://github.com/dlang/dmd/pull/10013). I don't see 
 an easy way to use it in function parameters.
It returning a tuple is not the problem because they auto expand : void foo(string a, int b, int c) { import std.stdio; writeln(a, " ", b); } void main() { foo(__traits(getLocation,foo)); } That you can't pass the caller loc is. A DIP will take a long time, I don't think the addition of __SYMBOLS__ require one. The addition of a type will possibly be problematic, but if `Loc` were a tuple that would be fine if we could do void foo(auto a = 1); since it would be just as silly to have to type void foo(typeof(__LOCATION__) loc = __LOCATION__);
Make a `Loc` type in the library: struct Loc { string file; int line; int column; } Make a helper to construct one: template getLoc(alias symbol) { enum getLoc = return Loc(__traits(getLocation, symbol)); }
I refactored my original idea and left it broken... it should be this: enum getLoc = Loc(__traits(getLocation, symbol));
3rd time's the charm! enum getLoc(alias symbol) = Loc(__traits(getLocation, symbol));
Yes,that's very interesting stuff to know about. Thank you so much for the valuable information.
Jul 31
prev sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 7/30/19 9:39 PM, Andrej Mitrovic wrote:
  From C++20: 
 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1208r5.pdf
 
 Instead of having to constantly declare "file = __FILE__, line = 
 __LINE__" everywhere, it would be so much more useful to just have a 
 single built-in type which we can default initialize . For example:
 
 -----
 import std.algorithm;
 
 void checkAndThrow (lazy bool expression, Loc loc = __LOCATION__)
 {
      if (!expression)
          throw new Exception("Failed", loc.file, loc.line);
 }
 
 void main ()
 {
      auto arr = [1, 1, 1, 1];
      checkAndThrow(arr.sum == 4);
 
      // should throw with file+line of this statement
      checkAndThrow(arr.sum == 5);
 }
 -----
This was my suggestion a while back: https://issues.dlang.org/show_bug.cgi?id=18919 The biggest problem I see with using string and size_t is that those are common parameter types that can be confused with actual parameters. Having a Location type solves that. -Steve
Aug 05
parent reply guy hebert <guyhebert143 outlook.com> writes:
On Monday, 5 August 2019 at 14:42:18 UTC, Steven Schveighoffer 
wrote:
 On 7/30/19 9:39 PM, Andrej Mitrovic wrote:
  From C++20: 
 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1208r5.pdf
 
 Instead of having to constantly declare "file = __FILE__, line 
 = __LINE__" everywhere, it would be so much more useful to 
 just have a single built-in type which we can default 
 initialize . For example:
 
 -----
 import std.algorithm;
 
 void checkAndThrow (lazy bool expression, Loc loc = 
 __LOCATION__)
 {
      if (!expression)
          throw new Exception("Failed", loc.file, loc.line);
 }
 
 void main ()
 {
      auto arr = [1, 1, 1, 1];
      checkAndThrow(arr.sum == 4);
 
      // should throw with file+line of this statement
      checkAndThrow(arr.sum == 5);
 }
 -----
This was my suggestion a while back: https://issues.dlang.org/show_bug.cgi?id=18919 The biggest problem I see with using string and size_t is that those are common parameter types that can be confused with actual parameters. Having a Location type solves that. http://www.crunchytricks.com/2016/07/offline-java-compilers.html -Steve
Have you got the solution.
Sep 24
parent reply Jacob Carlborg <doob me.com> writes:
On Tuesday, 24 September 2019 at 10:36:53 UTC, guy hebert wrote:

 Have you got the solution.
A __traits has been implemented: https://dlang.org/changelog/2.088.0.html#getloc -- /Jacob Carlborg
Sep 24
parent reply Stefan Koch <uplink.coder googlemail.com> writes:
On Tuesday, 24 September 2019 at 11:32:03 UTC, Jacob Carlborg 
wrote:
 On Tuesday, 24 September 2019 at 10:36:53 UTC, guy hebert wrote:

 Have you got the solution.
A __traits has been implemented: https://dlang.org/changelog/2.088.0.html#getloc -- /Jacob Carlborg
Does that solve the issue? can it stand in for the caller location?
Sep 24
parent reply FeepingCreature <feepingcreature gmail.com> writes:
On Tuesday, 24 September 2019 at 15:15:22 UTC, Stefan Koch wrote:
 On Tuesday, 24 September 2019 at 11:32:03 UTC, Jacob Carlborg 
 wrote:
 On Tuesday, 24 September 2019 at 10:36:53 UTC, guy hebert 
 wrote:

 Have you got the solution.
A __traits has been implemented: https://dlang.org/changelog/2.088.0.html#getloc -- /Jacob Carlborg
Does that solve the issue? can it stand in for the caller location?
No - how would you get the caller symbol? It's completely useless for this purpose. Personally I use Fence _ = Fence(), string file = __FILE__, size_t line = __LINE__, but that's obviously awkward in that it's not composable. Other things that don't work: void foo(Loc loc = Loc(__FILE__, __LINE__)), because __FILE__ and __LINE__ are substituted by explicitly checking whether the default value *is that symbol*. They cannot be composed. That's why we do need something like __LOCATION__. PS: You should ignore anyone on the topic unless they're linking a run.dlang.io with working code. PPS: https://run.dlang.io/is/B5eK59
Sep 25
parent Stefan Koch <uplink.coder googlemail.com> writes:
On Wednesday, 25 September 2019 at 07:16:21 UTC, FeepingCreature 
wrote:
 On Tuesday, 24 September 2019 at 15:15:22 UTC, Stefan Koch 
 wrote:
 On Tuesday, 24 September 2019 at 11:32:03 UTC, Jacob Carlborg 
 wrote:
 On Tuesday, 24 September 2019 at 10:36:53 UTC, guy hebert 
 wrote:

 Have you got the solution.
A __traits has been implemented: https://dlang.org/changelog/2.088.0.html#getloc -- /Jacob Carlborg
Does that solve the issue? can it stand in for the caller location?
No - how would you get the caller symbol? It's completely useless for this purpose
Sigh. I expected as much. Let's get a proper built-in location struct please.
Sep 25