digitalmars.D.learn - std.algorithm.countUntil and alias
- Anton Pastukhov (26/26) Oct 23 I'm struggling with this code. Why `countUntil` won't work with
- Paul Backus (29/55) Oct 23 The problem is that there's a compilation error inside the body
- Anton Pastukhov (4/5) Oct 23 Thanks, that's a good catch. `alias myAlias = MyStruct.test` is
- Paul Backus (8/16) Oct 23 You can't use an `alias` to refer to a member variable like this.
- Anton Pastukhov (5/13) Oct 23 Is it intended behavior? Is it documented somewhere? I'm looking
- monkyyy (6/26) Oct 23 Its intended and probably the right decision, but good luck
- Anton Pastukhov (3/5) Oct 23 What's the motivation behind it? For me, it looks like a weird
- H. S. Teoh (7/14) Oct 23 The key here is to understand that "alias" != "macro". If you're
- Anton Pastukhov (5/18) Oct 23 Well, I'm looking at Ali's book
- Anton Pastukhov (11/12) Oct 24 Re-reading this topic today and indeed that was the missing
- Jonathan M Davis (16/34) Oct 23 It aliases the symbol, but a member function does you no good without an
- Anton Pastukhov (11/51) Oct 23 Thanks for the clarification. I understand that aliasing a
- Paul Backus (13/31) Oct 23 Yes, it's intended.
- Salih Dincer (10/20) Oct 23 The code also compiles like this. In this case, can we say that
- Jonathan M Davis (21/24) Oct 23 static and enum are not the same thing.
- Salih Dincer (33/45) Oct 23 If it were me, I would equip my type with aliases like below. But
- Salih Dincer (30/33) Oct 23 I figured out why it wasn't working. It turns out I had made a
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]); } ```
Oct 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: ```d 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: ```d struct MyStruct { static Test test = Test.Three; } ``` The other is to use an instance of `MyTest` instead of an `alias`: ```d MyStruct myInstance; auto idx2 = countUntil!(e => e == myInstance.test)([EnumMembers!Test]); ```
Oct 23
On Wednesday, 23 October 2024 at 12:46:24 UTC, Paul Backus wrote:snipThanks, 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
Oct 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: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.snipThanks, 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
Oct 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.
Oct 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: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 formallyOn 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.
Oct 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
Oct 23
On Wed, Oct 23, 2024 at 06:10:07PM +0000, Anton Pastukhov via Digitalmars-d-learn wrote:On Wednesday, 23 October 2024 at 18:05:15 UTC, monkyyy wrote:The key here is to understand that "alias" != "macro". If you're looking for a way to shorten long expressions, `alias` is not what you're looking for. T -- Shin: (n.) A device for finding furniture in the dark.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
Oct 23
On Wednesday, 23 October 2024 at 18:39:15 UTC, H. S. Teoh wrote:On Wed, Oct 23, 2024 at 06:10:07PM +0000, Anton Pastukhov via Digitalmars-d-learn wrote:Well, I'm looking at Ali's book http://ddili.org/ders/d.en/alias.html and it states that, among other things, aliases are used to shorten long expressions. Not sure how authoritative it is thoOn Wednesday, 23 October 2024 at 18:05:15 UTC, monkyyy wrote:The key here is to understand that "alias" != "macro". If you're looking for a way to shorten long expressions, `alias` is not what you're looking for. TIts 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
Oct 23
On Wednesday, 23 October 2024 at 18:39:15 UTC, H. S. Teoh wrote:The key here is to understand that "alias" != "macro".Re-reading this topic today and indeed that was the missing piece. I was sure that alias is just a compile-time string replacement akin to C macros, just with some niceties such as type checking. Thanks to everyone commenting in this topic. For my initial question, I just ditched aliases and use full names instead. The underlying issue was my misunderstanding of the meaning of `symbol` as independently-addressable entity, and another misunderstanding of how `alias` works in D (and the fact that it's actually not just a macro).
Oct 24
On Wednesday, October 23, 2024 11:18:47 AM MDT Anton Pastukhov via Digitalmars-d-learn wrote:On Wednesday, 23 October 2024 at 14:50:44 UTC, Paul Backus wrote:It aliases the symbol, but a member function does you no good without an object to go with it. For the alias of a member function to actually be properly callable, it would need more than just the symbol. It would actually need to reference the object itself in some fashion, and that's simply not how aliases work. All they really do is provide an alternate name for a symbol. Really, it should probably just be illegal to alias a member function from a variable rather than the type, because the fact that it's allowed and then treated like it's an alias from the type causes confusion like you're experiencing. However, it's likely allowed for similar reasons to why it's legal to call static member functions on an instance rather than requiring that they be called on the type (which I'm inclined to argue was a bad design decision, but it's what we have). - Jonathan M DavisOn 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.
Oct 23
On Wednesday, 23 October 2024 at 19:10:05 UTC, Jonathan M Davis wrote:On Wednesday, October 23, 2024 11:18:47 AM MDT Anton Pastukhov via Digitalmars-d-learn wrote:Thanks for the clarification. I understand that aliasing a delegate would be problematic because it's context-aware. In my case, however, I'm aliasing not a delegate and not even a free function, I'm aliasing a struct field of enum type, which holds no references to the context. In my book it should be perfectly ok and inability to do so looks like a bug for me. Other participants mentioned that there is some rationale behind that design, so I'm just trying to understand it before heading to BugzillaOn Wednesday, 23 October 2024 at 14:50:44 UTC, Paul Backus wrote:It aliases the symbol, but a member function does you no good without an object to go with it. For the alias of a member function to actually be properly callable, it would need more than just the symbol. It would actually need to reference the object itself in some fashion, and that's simply not how aliases work. All they really do is provide an alternate name for a symbol. Really, it should probably just be illegal to alias a member function from a variable rather than the type, because the fact that it's allowed and then treated like it's an alias from the type causes confusion like you're experiencing. However, it's likely allowed for similar reasons to why it's legal to call static member functions on an instance rather than requiring that they be called on the type (which I'm inclined to argue was a bad design decision, but it's what we have). - Jonathan M DavisOn 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.
Oct 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:Yes, it's intended. A "symbol" in D means a named entity declared in the program's source code. While every instance of `MyStruct` has its own copy of the `test` member variable, there is only one *declaration* of `MyStruct.test`--and thus, only one symbol. In this case, instead of an `alias`, you can use a local function: ```d MyStruct myStruct; auto getTest() { return myStruct.test; } auto idx = countUntil!(e => e == getTest())(...); ```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.
Oct 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: ```d 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? ```d struct MyStruct { enum test = Test.Three } ``` SDB 79
Oct 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
Oct 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? ```d 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! ```d 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
Oct 23
On Wednesday, 23 October 2024 at 15:25:48 UTC, Salih Dincer wrote: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!I figured out why it wasn't working. It turns out I had made a size_t comparison with a string. In this case, it's smart to move away from string altogether and use alias fun(S). Here's D's perfect syntax: ```d struct Zoo(size_t i) { size_t count; static index = i; } void main() { enum Animal { dog = 3, cow, fox, cat } Animal[] animals; with(Animal) animals = [dog, cow, fox, cat]; alias myType = Zoo!(Animal.fox); alias fun(S) = e => e == S.index; import std.algorithm : countUntil; auto myStruct = myType( animals.countUntil!(fun!myType) ); assert(myStruct.index == 5); assert(myStruct.count == 2); import std.stdio; myStruct.writeln(": ", animals); // Zoo!5LU(2): [dog, cow, fox, cat] } ``` SDB 79
Oct 23