Jump to page: 1 2
Thread overview
October 23

I'm struggling with this code. Why countUntil won't work with aliases?

import std.traits : EnumMembers;
import std.algorithm : countUntil;

enum Test: string {
    One = "one",
    Two = "two",
    Three = "three"
}

struct MyStruct {
    Test test = Test.Three;
}

void main() {
    auto myStruct = MyStruct();

    // this works as expected
    auto idx = countUntil!(e => e == myStruct.test)([EnumMembers!Test]);

    // this triggers error: app.d(22): Error: none of the overloads of template `std.algorithm.searching.countUntil` are callable using argument types `!((e) => e == myAlias)(Test[])`
    alias myAlias = MyStruct.test;
    auto idx2 = countUntil!(e => e == myAlias)([EnumMembers!Test]);
}
October 23

On Wednesday, 23 October 2024 at 12:32:09 UTC, Anton Pastukhov wrote:

>

I'm struggling with this code. Why countUntil won't work with aliases?

import std.traits : EnumMembers;
import std.algorithm : countUntil;

enum Test: string {
    One = "one",
    Two = "two",
    Three = "three"
}

struct MyStruct {
    Test test = Test.Three;
}

void main() {
    auto myStruct = MyStruct();

    // this works as expected
    auto idx = countUntil!(e => e == myStruct.test)([EnumMembers!Test]);

    // this triggers error: app.d(22): Error: none of the overloads of template `std.algorithm.searching.countUntil` are callable using argument types `!((e) => e == myAlias)(Test[])`
    alias myAlias = MyStruct.test;
    auto idx2 = countUntil!(e => e == myAlias)([EnumMembers!Test]);
}

The problem is that there's a compilation error inside the body of your lambda, but it doesn't get displayed, because it happens inside a __traits(compiles) check (inside countUntil).

Attempting to call the lambda on its own, without using countUntil, reveals the error:

    alias myAlias = MyStruct.test;
    alias myLambda = e => e == myAlias;
    myLambda(Test.One);
    // Error: accessing non-static variable `test` requires an instance of `MyStruct`

There are two possible solutions to this. One is to make MyStruct.test a static variable:

// Solution #1
struct MyStruct {
    static Test test = Test.Three;
}

The other is to use an instance of MyTest instead of an alias:

    // Solution #2
    MyStruct myInstance;
    auto idx2 = countUntil!(e => e == myInstance.test)([EnumMembers!Test]);
October 23

On Wednesday, 23 October 2024 at 12:46:24 UTC, Paul Backus wrote:

>

snip

Thanks, that's a good catch. alias myAlias = MyStruct.test is really just a typo, I meant alias myAlias = myStruct.test, so I actually have an instance. It's still not compiling

October 23

On Wednesday, 23 October 2024 at 13:00:15 UTC, Anton Pastukhov wrote:

>

On Wednesday, 23 October 2024 at 12:46:24 UTC, Paul Backus wrote:

>

snip

Thanks, that's a good catch. alias myAlias = MyStruct.test is really just a typo, I meant alias myAlias = myStruct.test, so I actually have an instance. It's still not compiling

You can't use an alias to refer to a member variable like this. When you write

alias myAlias = myStruct.test;

...it is silently rewritten by the compiler to

alias myAlias = MyStruct.test;

So, in reality, there is no difference between the two versions.

October 23

On Wednesday, 23 October 2024 at 12:46:24 UTC, Paul Backus wrote:

>

On Wednesday, 23 October 2024 at 12:32:09 UTC, Anton Pastukhov wrote:

There are two possible solutions to this. One is to make MyStruct.test a static variable:

// Solution #1
struct MyStruct {
    static Test test = Test.Three;
}

The code also compiles like this. In this case, can we say that there are 3 solutions or are static and enum actually the same thing?

struct MyStruct {
  enum test = Test.Three
}

SDB@79

October 23

On Wednesday, 23 October 2024 at 12:32:09 UTC, Anton Pastukhov wrote:

>

I'm struggling with this code. Why countUntil won't work with aliases?

import std.traits : EnumMembers;
import std.algorithm : countUntil;

enum Test: string
{
    One = "one",
    Two = "two",
    Three = "three"
}

If it were me, I would equip my type with aliases like below. But for some reason I don't understand, the enum Numbers works, while the enum Test which is of type string doesn't!

import std.traits : EnumMembers;
import std.algorithm : countUntil;

enum Test: string
{
    One = "one",
    Two = "two",
    Three = "three"
}

enum Numbers: size_t
{
    One = 1, Two, Three
}

struct MyStruct(T) {
  enum tMax = T.max;
  size_t idx;
}

alias myType = Numbers; // Test; // not works!
void main()
{
  alias myAlias = MyStruct!myType;

  auto rng = [EnumMembers!myType];
  auto idx = rng.countUntil!(e => e == myAlias.tMax);

  auto myStruct = myAlias(idx);
  assert(myStruct.idx == 2);
}

SDB@79

October 23
On Wednesday, October 23, 2024 9:06:46 AM MDT Salih Dincer via Digitalmars-d- learn wrote:
> The code also compiles like this. In this case, can we say that there are 3 solutions or are static and enum actually the same thing?

static and enum are not the same thing.

An enum has no memory location, and you can't take its address. Rather, it's value is effectively copy-pasted wherever it's used (which is why using stuff like arrays for enums generally isn't a great idea, since that results in a bunch of allocations; string literals avoid that problem due to how the compiler handles those, but other array literals normally all result in allocations). enum values (rather than enum types) are called manifest constants and are essentially the D equivalent to when you use C's #define to declare a value.

A static variable on the other hand is a variable and has an address. So, whenever you use it, that variable is used, and you avoid allocations - but then you can't make the code that uses it pure unless the variable is immutable, since it could change, which goes against pure's inability to access global, mutable state.

The part that's the same between static variables and enums is that if they're directly initialized, that value has to be known at compile time. So, they both can be used in a variety of circumstances where you need to guarantee that something is done at compile time.

- Jonathan M Davis



October 23

On Wednesday, 23 October 2024 at 14:50:44 UTC, Paul Backus wrote:

>

On Wednesday, 23 October 2024 at 12:46:24 UTC, Paul Backus wrote:

>

You can't use an alias to refer to a member variable like this. When you write

alias myAlias = myStruct.test;

...it is silently rewritten by the compiler to

alias myAlias = MyStruct.test;

So, in reality, there is no difference between the two versions.

Is it intended behavior? Is it documented somewhere? I'm looking here https://dlang.org/spec/declaration.html#alias and it states: "An AliasDeclaration creates a symbol name that refers to a type or another symbol". myStruct.test is a symbol.

October 23

On Wednesday, 23 October 2024 at 17:18:47 UTC, Anton Pastukhov wrote:

>

On Wednesday, 23 October 2024 at 14:50:44 UTC, Paul Backus wrote:

>

On Wednesday, 23 October 2024 at 12:46:24 UTC, Paul Backus wrote:

>

You can't use an alias to refer to a member variable like this. When you write

alias myAlias = myStruct.test;

...it is silently rewritten by the compiler to

alias myAlias = MyStruct.test;

So, in reality, there is no difference between the two versions.

Is it intended behavior? Is it documented somewhere? I'm looking here https://dlang.org/spec/declaration.html#alias and it states: "An AliasDeclaration creates a symbol name that refers to a type or another symbol". myStruct.test is a symbol.

Its intended and probably the right decision, but good luck finding relivent docs.

id suggest passing a=>a.test to whatever function instead of trying to control the alias formally

October 23

On Wednesday, 23 October 2024 at 18:05:15 UTC, monkyyy wrote:

>

Its intended and probably the right decision, but good luck finding relivent docs.

What's the motivation behind it? For me, it looks like a weird edge case but I'm just probably missing something here

« First   ‹ Prev
1 2