Jump to page: 1 2
Thread overview
compile time 'address'
Nov 29, 2018
Dominic Jones
Nov 29, 2018
bauss
Nov 29, 2018
Dominic Jones
Nov 29, 2018
Stanislav Blinov
Nov 29, 2018
Stanislav Blinov
Nov 29, 2018
Alex
Nov 29, 2018
Dominic Jones
Nov 29, 2018
Dominic Jones
Nov 30, 2018
aliak
Nov 30, 2018
Dominic Jones
November 29, 2018
Hello,

I would like to capture the "address" of variables at compile time. Something not far from this can be done in C++, namely addresses can be compared but not captured (then compared, or whatever).

I was hoping that it could be done in D, so I wrote something similar to test. It seems that D is more restrictive than C++ in this matter, as even comparison cannot be performed at compile time, as far as I can tell.

What I wish to do may in principle not be possible, but I am not familiar enough with compilers to know for sure. Also, I am not so familiar with D, so a better transliteration from the C++ example maybe possible and yield something on par or better.

The reason for wanting to do all this is to find some way of 'baking in' the name of a variable (or some locally unique identifier) into an expression tree node type, facilitating certain expression tree transforms.

The closest I can get to what I want makes use of mixins, but is not ideal (https://run.dlang.io/is/Fr2b3f).


C++ (at: https://godbolt.org/z/CLPzGq)

template<typename T, typename U>
auto constexpr cmp(T const &t, U const &u)
{
/* Preferable, but not possible:
     auto constexpr ta = &t; // capture
     auto constexpr ua = &u;
     return ta == ua;
*/
  return &t == &u;
}

int main()
{
  auto c0 = 1;
  auto c1 = 2;

  static_assert(cmp(c0, c0));
  static_assert(!cmp(c0, c1));
}


D (at: https://run.dlang.io/is/rf5azp)

auto cmp(T, U)(const ref T t, const ref U u)
{
  return &t == &u;
}

void main()
{
  auto c0 = 1;
  auto c1 = 2;

  // error: "variable c0 cannot be read at compile time"
  static assert(cmp(c0, c0));
  static assert(!cmp(c0, c1));
}
November 29, 2018
On Thursday, 29 November 2018 at 15:56:54 UTC, Dominic Jones wrote:
> Hello,
>
> I would like to capture the "address" of variables at compile time. Something not far from this can be done in C++, namely addresses can be compared but not captured (then compared, or whatever).
>
> I was hoping that it could be done in D, so I wrote something similar to test. It seems that D is more restrictive than C++ in this matter, as even comparison cannot be performed at compile time, as far as I can tell.
>
> What I wish to do may in principle not be possible, but I am not familiar enough with compilers to know for sure. Also, I am not so familiar with D, so a better transliteration from the C++ example maybe possible and yield something on par or better.
>
> The reason for wanting to do all this is to find some way of 'baking in' the name of a variable (or some locally unique identifier) into an expression tree node type, facilitating certain expression tree transforms.
>
> The closest I can get to what I want makes use of mixins, but is not ideal (https://run.dlang.io/is/Fr2b3f).
>
>
> C++ (at: https://godbolt.org/z/CLPzGq)
>
> template<typename T, typename U>
> auto constexpr cmp(T const &t, U const &u)
> {
> /* Preferable, but not possible:
>      auto constexpr ta = &t; // capture
>      auto constexpr ua = &u;
>      return ta == ua;
> */
>   return &t == &u;
> }
>
> int main()
> {
>   auto c0 = 1;
>   auto c1 = 2;
>
>   static_assert(cmp(c0, c0));
>   static_assert(!cmp(c0, c1));
> }
>
>
> D (at: https://run.dlang.io/is/rf5azp)
>
> auto cmp(T, U)(const ref T t, const ref U u)
> {
>   return &t == &u;
> }
>
> void main()
> {
>   auto c0 = 1;
>   auto c1 = 2;
>
>   // error: "variable c0 cannot be read at compile time"
>   static assert(cmp(c0, c0));
>   static assert(!cmp(c0, c1));
> }

Use enum instead of auto.
November 29, 2018
On 11/29/18 10:56 AM, Dominic Jones wrote:
> Hello,
> 
> I would like to capture the "address" of variables at compile time. Something not far from this can be done in C++, namely addresses can be compared but not captured (then compared, or whatever).
> 
> I was hoping that it could be done in D, so I wrote something similar to test. It seems that D is more restrictive than C++ in this matter, as even comparison cannot be performed at compile time, as far as I can tell.
> 
> What I wish to do may in principle not be possible, but I am not familiar enough with compilers to know for sure. Also, I am not so familiar with D, so a better transliteration from the C++ example maybe possible and yield something on par or better.
> 
> The reason for wanting to do all this is to find some way of 'baking in' the name of a variable (or some locally unique identifier) into an expression tree node type, facilitating certain expression tree transforms.
> 
> The closest I can get to what I want makes use of mixins, but is not ideal (https://run.dlang.io/is/Fr2b3f).
> 
> 
> C++ (at: https://godbolt.org/z/CLPzGq)
> 
> template<typename T, typename U>
> auto constexpr cmp(T const &t, U const &u)
> {
> /* Preferable, but not possible:
>       auto constexpr ta = &t; // capture
>       auto constexpr ua = &u;
>       return ta == ua;
> */
>    return &t == &u;
> }
> 
> int main()
> {
>    auto c0 = 1;
>    auto c1 = 2;
> 
>    static_assert(cmp(c0, c0));
>    static_assert(!cmp(c0, c1));
> }
> 
> 
> D (at: https://run.dlang.io/is/rf5azp)
> 
> auto cmp(T, U)(const ref T t, const ref U u)
> {
>    return &t == &u;
> }
> 
> void main()
> {
>    auto c0 = 1;
>    auto c1 = 2;
> 
>    // error: "variable c0 cannot be read at compile time"
>    static assert(cmp(c0, c0));
>    static assert(!cmp(c0, c1));
> }

So this is a combination of 2 problems.

1. No you cannot read c0 or c1 at compile time, because they are runtime values. You can fix this by changing them to immutable or enum.

2. D doesn't like you taking the address of compile-time values, but the error message is really bad.

If I do this:

auto cmp(T, U)(const T t, const U u) // note, no ref
{
  return t == u; // note, change to value not address
}

void main()
{
  immutable c0 = 1; // note change to immutable
  immutable c1 = 2;

  // these now work.
  static assert(cmp(c0, c0));
  static assert(!cmp(c0, c1));
}

If I don't change away from ref, it complains that it can't read c0 or c1 at compile time, which clearly is shown to be readable at compile time.

I think the error message should be more like "Cannot use reference to this variable at compile-time".

-Steve
November 29, 2018
Hello Steve,

Thank you for your comments. A couple of replies:


On Thursday, 29 November 2018 at 16:29:00 UTC, Steven Schveighoffer wrote:
> 1. No you cannot read c0 or c1 at compile time, because they are runtime values. You can fix this by changing them to immutable or enum.

The variables are deliberately 'auto' rather than 'auto constexpr' as per the C++ example, so I do wish to preserve that in the D example. Nevertheless, in C++ querying (at least to perform comparison) the sudo-address, whatever it is (perhaps, behind the scenes it is simply a stack frame offset), is permitted.


> 2. D doesn't like you taking the address of compile-time values, but the error message is really bad.
>
> If I do this:
>
> auto cmp(T, U)(const T t, const U u) // note, no ref
> {
>   return t == u; // note, change to value not address
> }

Presumably, this is now simply comparing values held by the variables, rather than the sudo-address of the original variables as per the C++ example?
November 29, 2018
On 11/29/18 12:59 PM, Dominic Jones wrote:
> Hello Steve,
> 
> Thank you for your comments. A couple of replies:
> 
> 
> On Thursday, 29 November 2018 at 16:29:00 UTC, Steven Schveighoffer wrote:
>> 1. No you cannot read c0 or c1 at compile time, because they are runtime values. You can fix this by changing them to immutable or enum.
> 
> The variables are deliberately 'auto' rather than 'auto constexpr' as per the C++ example, so I do wish to preserve that in the D example. Nevertheless, in C++ querying (at least to perform comparison) the sudo-address, whatever it is (perhaps, behind the scenes it is simply a stack frame offset), is permitted.
> 
> 
>> 2. D doesn't like you taking the address of compile-time values, but the error message is really bad.
>>
>> If I do this:
>>
>> auto cmp(T, U)(const T t, const U u) // note, no ref
>> {
>>   return t == u; // note, change to value not address
>> }
> 
> Presumably, this is now simply comparing values held by the variables, rather than the sudo-address of the original variables as per the C++ example?

Ah, ok. Essentially you are looking for the layout of the local variables.

One thing that is available for D is the compile-time property offsetof, which gives the offset from the start of an aggregate that an item is.

for example:

struct S
{
  int x;
  bool y;
}

static assert(S.y.offsetof == 4);

So while this isn't available for function locals, the idea is similar. But I don't think there's an equivalent to what you are able to do here in C++.

I don't think it would be a huge stretch to apply this same property to function locals, but it would require an enhancement request.

-Steve
November 29, 2018
On Thursday, 29 November 2018 at 18:49:27 UTC, Steven Schveighoffer wrote:

> I don't think it would be a huge stretch to apply this same property to function locals, but it would require an enhancement request.
>
> -Steve

This compiles since 2.069.2 (according to run.dlang.io):

void main() {
    auto c0 = 1;
    auto c1 = 2;
    static assert(&c0 == &c0);
    static assert(&c0 != &c1);
}

I wonder if that is a bug, or that the original question not compiling is :D
November 29, 2018
On 11/29/18 2:16 PM, Stanislav Blinov wrote:
> On Thursday, 29 November 2018 at 18:49:27 UTC, Steven Schveighoffer wrote:
> 
>> I don't think it would be a huge stretch to apply this same property to function locals, but it would require an enhancement request.
>>
> 
> This compiles since 2.069.2 (according to run.dlang.io):
> 
> void main() {
>      auto c0 = 1;
>      auto c1 = 2;
>      static assert(&c0 == &c0);
>      static assert(&c0 != &c1);
> }
> 
> I wonder if that is a bug, or that the original question not compiling is :D

I think the issue is that D is expecting you to be able to use the value pointed at possibly in the function, which would normally be fully available at CTFE (the two variables are runtime variables).

There's no way to accept a pointer that can't be used, just the value of the pointer checked.

I'm not sure how it would work exactly. I suppose you could accept void *, I don't know if it's possible to recast in CTFE?

-Steve
November 29, 2018
On Thursday, 29 November 2018 at 20:22:16 UTC, Steven Schveighoffer wrote:

>> This compiles since 2.069.2 (according to run.dlang.io):
>> 
>> void main() {
>>      auto c0 = 1;
>>      auto c1 = 2;
>>      static assert(&c0 == &c0);
>>      static assert(&c0 != &c1);
>> }
>> 
>> I wonder if that is a bug, or that the original question not compiling is :D
>
> I think the issue is that D is expecting you to be able to use the value pointed at possibly in the function, which would normally be fully available at CTFE (the two variables are runtime variables).
>
> There's no way to accept a pointer that can't be used, just the value of the pointer checked.

Yeah, but this one seems a bit deliberate. The asserts hold, but you can't e.g.

enum diff = &c0 - &c1; // 'c0' can't be used at compile time

> I'm not sure how it would work exactly. I suppose you could accept void *, I don't know if it's possible to recast in CTFE?

It isn't.
November 29, 2018
On Thursday, 29 November 2018 at 21:00:57 UTC, Stanislav Blinov wrote:
>
> Yeah, but this one seems a bit deliberate. The asserts hold, but you can't e.g.
>
> enum diff = &c0 - &c1; // 'c0' can't be used at compile time

What would you say to this:
https://forum.dlang.org/thread/tdmkajpnqkbywdnzddqc@forum.dlang.org
November 29, 2018
On Thursday, 29 November 2018 at 21:00:57 UTC, Stanislav Blinov wrote:

>> There's no way to accept a pointer that can't be used, just the value of the pointer checked.
>
> Yeah, but this one seems a bit deliberate. The asserts hold, but you can't e.g.
>
> enum diff = &c0 - &c1; // 'c0' can't be used at compile time

This is the same situation as C++; the addresses can only be compared (with == or !=). Any attempt to capture their values first will cause a compilation failure, i.e. attempting:

  // "error: '& t' is not a constant expression", etc
  auto constexpr ta = &t;
  auto constexpr ua = &u;
  return ta == ua;

« First   ‹ Prev
1 2