Re: What prevents ImportC from using .h directly?
On Sunday, 12 May 2024 at 21:34:30 UTC, Chris Piker wrote: So, why does ImportC need *.c files exclusively? I'm sure it solves a problem, but I don't know what that problem is. Support for headers has been worked on, but had to be reverted: https://issues.dlang.org/show_bug.cgi?id=23479
What prevents ImportC from using .h directly?
Hi D Import D is working quite well so far. One limitation is that module definitions require a tiny *.c file which is often just: ```C #include ``` Creating this file is trivial and has almost no knock-on effects, except when dealing with single file programs. I have quite a few small utilities with dub headers. It would be handy if I could set an import path and use ImportC on the header file directly, skipping the small C file all together. A specific example in my case follows. Given a C-lib interface defined in the header file: ``` /usr/include/cspice/SpiceUsr.h ``` it would be neat if a dub header similar to the following worked: ```d #!/usr/bin/env dub /+ dub.sdl: name "some_app" cImportPaths "/usr/local/include/cspice" +/ import SpiceUsr; // ... source continues ``` So, why does ImportC need *.c files exclusively? I'm sure it solves a problem, but I don't know what that problem is.
Re: What I thought was straightforward blew up in my face..
```c void SDL_GetVersion(SDL_version * ver); ``` It doesn't return anything. Its return type is void. See the argument list where it lists the types of the arguments: ``template writeln is not callable using argument types !()(string, void)`` Which aligns with the arguments you passed to ``writeln``.
What I thought was straightforward blew up in my face..
import bindbc.sdl; import bindbc.loader; SDL_version ver; SDL_GetVersion(); writeln("version = ", ver); // runs and displays: version = SDL_version(2, 30, 2) writeln("version = ", SDL_GetVersion()); // compile fails with // template `writeln` is not callable using argument types `!()(string, void)` // C:\D\dmd2\windows\bin64\..\..\src\phobos\std\stdio.d(4249,6): Candidate is: `writeln(T...)(T args)` // Error C:\D\dmd2\windows\bin64\dmd.exe failed with exit code 1. I'll confess I can't make heads or tails out of the error messages. Is this impossible or is there some way to make writeln happy?
Re: what was the problem with the old post blit operator already ?
It was mostly fine, such types are not supposed to be immutable, but recently came an idea of reference counted strings, which need to be immutable for being strings.
Re: what was the problem with the old post blit operator already ?
On Thursday, 15 February 2024 at 03:17:11 UTC, Jonathan M Davis wrote: On Wednesday, February 14, 2024 7:17:15 PM MST Basile B. via Digitalmars-d- learn wrote: From what I remember, it was that there was no reference to the source. Things got blitted and you had to fix the copy, already blitted. Was that the only issue ? There were probably some use cases where you needed access to both the source and the destination so that you could do something to the source as well, but the core problem was simply that blitting and then mutating the copy to fix it doesn't work with const or immutable objects, since it would violate the type system to cast away const or immutable to fix the copy. The only way to work properly with const or immutable is to construct the object with the changes in the first place rather than mutating the copy after the fact. - Jonathan M Davis That point was raised by Teoh too, which raises another question. Did the "old" postblit exist before the introduction of type qualifiers ? I think to D1 obviously. That would suggest that the introduction of type qualifiers was not perfectly executed, i.e some aspects were not mastered, until, years after, someone said "wait a minute, there's something wrong".
Re: what was the problem with the old post blit operator already ?
On Wednesday, February 14, 2024 7:17:15 PM MST Basile B. via Digitalmars-d- learn wrote: > From what I remember, it was that there was no reference to the > source. Things got blitted and you had to fix the copy, already > blitted. Was that the only issue ? There were probably some use cases where you needed access to both the source and the destination so that you could do something to the source as well, but the core problem was simply that blitting and then mutating the copy to fix it doesn't work with const or immutable objects, since it would violate the type system to cast away const or immutable to fix the copy. The only way to work properly with const or immutable is to construct the object with the changes in the first place rather than mutating the copy after the fact. - Jonathan M Davis
Re: what was the problem with the old post blit operator already ?
On Thu, Feb 15, 2024 at 02:17:15AM +, Basile B. via Digitalmars-d-learn wrote: > From what I remember, it was that there was no reference to the > source. Things got blitted and you had to fix the copy, already > blitted. Was that the only issue ? I don't quite remember all of the reasons now. But yeah, one of the problems with postblit was that you don't have access to the original copy. That precludes some applications where you need to look up data from the original or update the original. And if you have immutable fields they've already been blitted and you can't fix them anymore, not without casting away immutable and putting yourself in UB zone. There may have been other issues with postblit, I don't quite remember now. T -- Beware of bugs in the above code; I have only proved it correct, not tried it. -- Donald Knuth
Re: Safety is not what you think
On Monday, 5 February 2024 at 14:26:45 UTC, Basile B. wrote: On Tuesday, 30 January 2024 at 15:38:26 UTC, Paul Backus wrote: [...] This definitely isn't allowed in C or C++. I wonder what the rationale is for having this behavior in D? [1]: https://dlang.org/spec/expression.html An hypothesis is that this makes codegening the pre and the post variants almost identical. The only difference is what is yield. [Proof](https://gitlab.com/styx-lang/styx/-/blob/master/src/styx/backend/irgen.sx?ref_type=heads#L3383). Now there's not much to say about the topic, I just thought it was amusing to share that (user1234 is my noname nickname here) as people might not realize how much certain expressions allows. In the same vein you have the possibility to select an lvalue with a conditional expression. Pretty sure nobody knows that the following is legal ```d int a,b; int c = rand(); ((c & 3) ? a : b) = 42; ``` BTW, "achtung off topic", that's pretty much how the optional access can be an lvalue: ```d struct S {int a}; S* s; // null, by default init s?.a = 0; // no access violation !! + valgrind is happy ``` You can lower that to a conditional expression: ```d struct S {int a}; S* s; typeof(S.a) __fallback; // compiler-generated (s ? s.a : __fallback) = 0; ``` I've played a lot with that kind of expressions during the two last years. They're funny but apparently not good enough for D ;) To conclude.
Re: Safety is not what you think
On Tuesday, 30 January 2024 at 15:38:26 UTC, Paul Backus wrote: [...] This definitely isn't allowed in C or C++. I wonder what the rationale is for having this behavior in D? [1]: https://dlang.org/spec/expression.html An hypothesis is that this makes codegening the pre and the post variants almost identical. The only difference is what is yield. [Proof](https://gitlab.com/styx-lang/styx/-/blob/master/src/styx/backend/irgen.sx?ref_type=heads#L3383). Now there's not much to say about the topic, I just thought it was amusing to share that (user1234 is my noname nickname here) as people might not realize how much certain expressions allows. In the same vein you have the possibility to select an lvalue with a conditional expression. Pretty sure nobody knows that the following is legal ```d int a,b; int c = rand(); ((c & 3) ? a : b) = 42; ```
Re: Safety is not what you think
On Tuesday, 30 January 2024 at 15:38:26 UTC, Paul Backus wrote: This definitely isn't allowed in C or C++. I wonder what the rationale is for having this behavior in D? It isn't allowed in C, but allowed in C++ https://godbolt.org/z/9xTPhsb5G As for rationale... I don't know why it wouldn't be allowed? You clearly need an lvalue to use prefix ++, and the result is the value after adding one, so why can't it be bound to a reference? I don't see where the problem would arise. -Steve
Re: Safety is not what you think
On Tuesday, 30 January 2024 at 02:05:23 UTC, user1234 wrote: I want to share a stupid program to show you that D safety is more complex than you might think: ```d module test; void test() @safe { int i; int b = (*&(*&++i))++; } void main() @safe { test(); } ``` I'm not showing a deficiency of D, that program is undeniably safe ;) I'm surprised `&++i` even compiles in the first place, but looking at [the spec][1], it seems to be intentional: The following expressions, and no others, are called lvalue expressions or lvalues: [...] 4. the result of the following expressions: * built-in unary operators + (when applied to an lvalue), *, ++ (prefix only), -- (prefix only); Testing it out, the address you get is the same as ``. This definitely isn't allowed in C or C++. I wonder what the rationale is for having this behavior in D? [1]: https://dlang.org/spec/expression.html
Safety is not what you think
I want to share a stupid program to show you that D safety is more complex than you might think: ```d module test; void test() @safe { int i; int b = (*&(*&++i))++; } void main() @safe { test(); } ``` I'm not showing a deficiency of D, that program is undeniably safe ;)
Re: D Phobos Library Documentation: What is the Internal API for?
On Monday, November 27, 2023 6:03:22 AM MST BoQsc via Digitalmars-d-learn wrote: > This is pretty basic question. > If you open [D Library > Reference](https://dlang.org/phobos/index.html) you are bound to > see the **Internal API** section in the table of content. > > What is the **Internal API** (internal.core, dmd, rt) for and > when, how and where to use it? > > ![](https://i.imgur.com/WyemZsG.png) They're modules that are supposed to be internal to the implementation. They should not be accessible to anyone outside of those projects. So, it's pretty weird that it's up on the website, but my guess is that someone put it there so that the folks working on the code base could see the rendered ddoc comments for that code. For instance, I could believe that the dmd section there is there just to make it easier for some of the folks working on the compiler to more easily get an overview of the public symbols within those modules. But if you're not contributing to those projects, there really isn't any reason to see those modules. - Jonathan M Davis
D Phobos Library Documentation: What is the Internal API for?
This is pretty basic question. If you open [D Library Reference](https://dlang.org/phobos/index.html) you are bound to see the **Internal API** section in the table of content. What is the **Internal API** (internal.core, dmd, rt) for and when, how and where to use it? ![](https://i.imgur.com/WyemZsG.png)
Re: What is :-) ?
On Monday, 20 November 2023 at 16:47:13 UTC, Paul Backus wrote: You can put the `delegate` keyword in front of the function literal: ```d auto createCounter = delegate (int nextValue) => () => nextValue++; ``` This syntax is documented in the spec's section on [Function Literals][2] (look at the grammar box and the examples). [2]: https://dlang.org/spec/expression.html#function_literals Thaks Paul
Re: What is :-) ?
On Monday, 20 November 2023 at 16:32:22 UTC, evilrat wrote: ```d // this is a function returning a delegate auto createCounter(int nextValue) => auto delegate() => nextValue++; Thank you!!!. Compiler forces me to omit "auto" keyword ```d auto createCounter(int nextValue) => delegate () => nextValue++ ; ``` Explicit return must be specified after "delegate" keyword ```d auto createCounter(int nextValue) => delegate int () => nextValue++ ; ``` When declaring a type (variable or parameter) is when keywords order must be "inverted" ```d import std.stdio; int callWith10( int delegate (int) x) =>x(10); void main(){ int j=100; // Explicit writeln( callWith10( delegate int (int i)=>i+j ) ); // Inferred writeln( callWith10( i=>i+j ) ); // OMG writeln( ( i=>i+j ).callWith10 ); } ``` // this is a function returning a function auto createCounter(int nextValue) => auto function() => nextValue++; ``` I think this will not work, because nextValue is defined out of the returned function scope: you must return a closure (delegate). Thanks a lot evilrat!!! **From your answer (and other ones too) I have to say that...** * **D Closures rocks!!!** It is hard to find something so powerful in other natively compiled languages: **Heap + GC** has it's advantages. * **D offers nice syntax features**: you can declare arrow methods very similar to dart, or assign an arrow function/delegate to a variable like Javascript/Typescript lambdas.
Re: What parser generator can let me run arbitrary code in its match rules?
On Monday, 20 November 2023 at 23:50:24 UTC, Dmitry Ponyatov wrote: - not abandoned years ago - documentation and commented samples presenets - CTFE the best https://code.dlang.org/packages/pegged
Re: What parser generator can let me run arbitrary code in its match rules?
On Monday, 20 November 2023 at 23:56:36 UTC, Dmitry Ponyatov wrote: Or maybe someone advice me some set of books deeply targets for learning of binary and symmetric parsing (such as binpac), DCG in C or using generators in D, etc to let me write my own lib. 'Crafting Interpreters' book explain recursive descent parser, including parsing binary operators with priorities.
Re: What parser generator can let me run arbitrary code in its match rules?
Or maybe someone advice me some set of books deeply targets for learning of binary and symmetric parsing (such as binpac), DCG in C or using generators in D, etc to let me write my own lib. Everething I found (besides the Dragon book) uses black magic with Haskell, Lisp etc.
What parser generator can let me run arbitrary code in its match rules?
- not abandoned years ago - documentation and commented samples presenets - CTFE the best
Re: What is :-) ?
On Monday, 20 November 2023 at 16:09:33 UTC, Antonio wrote: **Why this is a function and not a delegate?** ```auto createCounter = (int nextValue) => (int dummy) => nextValue++;``` Syntactically I dont see any difference: `createCounter` is a function, and not a delegate, as it doesn't close over any variables. It returns a delegate as the variable `nextValue` is closed over. There's no difference in syntax. The difference is however important as an environment must be retained for the closed-over variables and passed along with the pointer, making delegates both more expensive and incompatible with function pointers on the C ABI. Note that `f` and `g` are obviously not pointing to the same `nextValue`: ```d auto createCounter = (int nextValue) => () => nextValue++; void main() { import std.stdio : writeln; auto f = createCounter(5); auto g = createCounter(0); writeln(f()); // 5 writeln(g()); // 0 writeln(f()); // 6 writeln(g()); // 1 } ``` What "breaks" my mind is that a compiler decision (treat a piece of code as function or delegate) is not completely transparent D is trying to be convenient (by offering delegates at all, and by making the syntax so light) while offering fine control (by letting you distinguish between function pointers and delegates). It'd be a much simpler language if it dropped one of those aims, but such languages also already exist. Similarly D also distinguishes between "numbers" (`int`) and "numbers" (`double`) and this can also be transparent and also cause 'side effects'. Someone educated in mathematics but not familiar with computing might complain about ```d void main() { import std.stdio : writefln; auto n = 1; writefln!"%d"(n); } ``` breaking when "all I did was bump n by one-tenth, to 1.1". I'm not trying to be mean with this example, and I don't think it's shameful either to know mathematics but not computing. But D expects you to be familiar with such things for you to not be surprised by how it behaves.
Re: What is :-) ?
On Monday, 20 November 2023 at 16:09:33 UTC, Antonio wrote: What "breaks" my mind is that a compiler decision (treat a piece of code as function or delegate) is not completely transparent causing "side" effects on your code (writeln doesn't work the same way: it shows the delegate signature, but not the function signature). It's certainly surprising that `writeln` treats function pointers and delegates differently. My guess is that it's because [`isPointer`][1] returns `true` for functions and `false` for delegates. [1]: https://phobos.dpldocs.info/std.traits.isPointer.html Is there any way to force D compiler to treat this "createCounter" declaration as **delegate** instead of **function**? ```d auto createCounter = (int nextValue) => () => nextValue++; ``` You can put the `delegate` keyword in front of the function literal: ```d auto createCounter = delegate (int nextValue) => () => nextValue++; ``` This syntax is documented in the spec's section on [Function Literals][2] (look at the grammar box and the examples). [2]: https://dlang.org/spec/expression.html#function_literals
Re: What is :-) ?
On Monday, 20 November 2023 at 16:09:33 UTC, Antonio wrote: Is there any way to force D compiler to treat this "createCounter" declaration as **delegate** instead of **function**? ```d auto createCounter = (int nextValue) => () => nextValue++; ``` generally there is a way to tell the compiler specifically that you want a delegate or a function, and additionally there is `toDelegate` function from std.functional that could be useful in some cases. https://dlang.org/phobos/std_functional.html#toDelegate the syntax for specifying delegate/function is smth like this, IIRC return type can be omitted but for reference I write it here as auto. ```d // this is a function returning a delegate auto createCounter(int nextValue) => auto delegate() => nextValue++; // this is a function returning a function auto createCounter(int nextValue) => auto function() => nextValue++; ```
Re: What is :-) ?
On Monday, 20 November 2023 at 13:25:48 UTC, Paul Backus wrote: On Monday, 20 November 2023 at 08:47:34 UTC, Antonio wrote: - What is the way to do ```writeln``` work with ```Counter``` function the same way it works with ```next``` function? `writeln()` should do it. It does not do the same: It shows an address, not the function signature. Because I need to understand "why", I propose a second example (with some additional info based on @evilrat proposals :-) ): ```d import std.stdio; void main() { auto createCounter = (int nextValue) => (int dummy) => nextValue++; auto getNext = createCounter(10); writeln( "'getNext' is ", getNext ); writeln( "'createCounter' is ", createCounter ); writeln( "'typeof(getNext).stringof' is ", typeof(getNext).stringof ); writeln( "'typeof(createCounter).string' is ", typeof(createCounter).stringof ); } ``` The output is ``` 'next' is int delegate(int) pure nothrow @nogc @safe 'createCounter' is 557FFCC00968 'typeof(getNext).stringof' is int delegate(int dummy) pure nothrow @nogc @safe 'typeof(createCounter).string' is int delegate(int dummy) pure nothrow @nogc @safe function(int nextValue) pure nothrow @safe ``` **Why ```writeln``` doesn't treat the same way ```getNext``` and ```createCounter```?** Because ```getNext``` is a delegate and ```createCounter``` is a function. **Why this is a function and not a delegate?** ```auto createCounter = (int nextValue) => (int dummy) => nextValue++;``` Syntactically I dont see any difference: ```auto name = "expression returning a delegate"``` The reason is **D compiler takes the decision**. If you make ```createCounter``` to depend on an external variable, it will be treated as delegate (because it has context information associated to the function: a closure) ```d import std.stdio; void main() { int diff = 1; auto createCounter = (int nextValue) => () { scope(exit) nextValue+=diff; return nextValue;}; writeln( "'typeof(createCounter).string' is ", typeof(createCounter).stringof ); } ``` Will output that createCounter is a delegate: ``` 'typeof(createCounter).string' is int delegate() pure nothrow @nogc @safe delegate(int nextValue) pure nothrow @safe ``` What "breaks" my mind is that a compiler decision (treat a piece of code as function or delegate) is not completely transparent causing "side" effects on your code (writeln doesn't work the same way: it shows the delegate signature, but not the function signature). But the decision of the compiler is predictable and you can argue different effects are not side effects: only something you should pay attention to. **This long and winding road toke me to a third and crazzy question** Is there any way to force D compiler to treat this "createCounter" declaration as **delegate** instead of **function**? ```d auto createCounter = (int nextValue) => () => nextValue++; ```
Re: What is :-) ?
On Monday, 20 November 2023 at 08:47:34 UTC, Antonio wrote: - What is the way to do ```writeln``` work with ```Counter``` function the same way it works with ```next``` function? `writeln()` should do it.
Re: What is :-) ?
On Monday, 20 November 2023 at 08:47:34 UTC, Antonio wrote: I understand the problem with UFCS (``next`` is not using UFCS because it is a delegate defined in the own main() function, and ``Counter``` without () is treated as a function call because it is UFCS eligible ) This is not UFCS, it's [optional parentheses][1], which is a separate language feature. (Reminder: UFCS only applies when the callee has the form `x.y`) According to the spec, it's disabled for function pointers and delegates due to the potential for ambiguity. [1]: https://dlang.org/spec/function.html#optional-parenthesis
Re: What is :-) ?
On Monday, 20 November 2023 at 09:44:32 UTC, Antonio wrote: - Why writeln doesn't treat ```next``` and ```Counter``` the same way? (I think I understand why, but it shows a "low" level difference of something that syntactically is equivalent) - What is the way to show Counter signature using ```writeln``` (if possible)? I found no way to tell compiler that I don't want to call Counter and instead want to take the function itself, but closest thing is just to take the string representation at compile time (same as used in pragma msg) and pass it to writeln instead of Counter. I guess this is one of these bif oof moments with UFCS, a function returning a (parameterless) function. Note that in most cases you should never make runtime decisions on .stringof value as it is not standardized. ``` //pragma(msg, typeof(Counter)); // pure nothrow @safe int delegate() pure nothrow @nogc @safe(int nextValue) enum f = typeof(Counter).stringof; // same string as above writeln( "'Counter' is ", f); ``` Of course this works too `writeln( "'Counter' is ", typeof(Counter).stringof);`
Re: What is :-) ?
On Monday, 20 November 2023 at 09:11:07 UTC, evilrat wrote: if you meant to take the function/delegate and not invoke try `` instead, otherwise it expects the parameters. If you execute ``` writeln( "'Counter' is ", ); ``` It shows the Counter address: ``` 'Counter' is 557F2567F940 ``` Not the function signature like it does with ```next``` I propose a simple change: ```d void main(){ auto Counter = (int nextValue) => () => nextValue++; auto next = Counter(10); writeln( "'next' is ", next ); writeln( "'Counter' is ", Counter ); } ``` first ```writeln``` shows the signature of next: ``` 'next' is int delegate() pure nothrow @nogc @safe ``` second writeln shows the address of Counter ``` 'Counter' is 55568953C910 ``` - Why writeln doesn't treat ```next``` and ```Counter``` the same way? (I think I understand why, but it shows a "low" level difference of something that syntactically is equivalent) - What is the way to show Counter signature using ```writeln``` (if possible)? ```
Re: What is :-) ?
On Monday, 20 November 2023 at 08:47:34 UTC, Antonio wrote: Now, I uncomment the ```writeln( "'Counter' is ", Counter );``` line and compiler says ``` /home/antonio/Devel/topbrokers/whatsapp-srv/admin/x.d(12): Error: function `x.Counter(int nextValue)` is not callable using argument types `()` /home/antonio/Devel/topbrokers/whatsapp-srv/admin/x.d(12): too few arguments, expected 1, got 0 ``` I understand the problem with UFCS (``next`` is not using UFCS because it is a delegate defined in the own main() function, and ``Counter``` without () is treated as a function call because it is UFCS eligible ) `writeln( "'Counter' is ", Counter );` this code is actually internally looks like this `writeln( "'Counter' is ", Counter() );` if you meant to take the function/delegate and not invoke try `` instead, otherwise it expects the parameters. - What is the way to do ```writeln``` work with ```Counter``` function the same way it works with ```next``` function? Sorry, that's too confusing and I have no idea what you mean, maybe if you can explain what you are trying to achieve someone might be able to help you.
What is :-) ?
If I run this code ```d import std.stdio; void main(){ auto next = Counter(10); next().writeln; next().writeln; next().writeln; // What is "next" function? writeln( "'next' is ", next ); // What is "Counter" function? This fails // writeln( "'Counter' is ", Counter ); } auto Counter(int nextValue) => () => nextValue++; ``` Executing this code results in: ``` 10 11 12 'next' is int delegate() pure nothrow @nogc @safe ``` Now, I uncomment the ```writeln( "'Counter' is ", Counter );``` line and compiler says ``` /home/antonio/Devel/topbrokers/whatsapp-srv/admin/x.d(12): Error: function `x.Counter(int nextValue)` is not callable using argument types `()` /home/antonio/Devel/topbrokers/whatsapp-srv/admin/x.d(12): too few arguments, expected 1, got 0 ``` I understand the problem with UFCS (``next`` is not using UFCS because it is a delegate defined in the own main() function, and ``Counter``` without () is treated as a function call because it is UFCS eligible ) - What is the way to do ```writeln``` work with ```Counter``` function the same way it works with ```next``` function?
Re: What are the best available D (not C) File input/output options?
On 11/3/23 2:30 AM, Steven Schveighoffer wrote: On Thursday, 2 November 2023 at 15:46:23 UTC, confuzzled wrote: You should use a buffering library like iopipe to write properly here (it handles the encoding of text for you). Thanks Steve, I will try that.
Re: What are the best available D (not C) File input/output options?
Good morning, First, thanks to you, Steve, and Julian for responding to my inquiry. On 11/3/23 4:59 AM, Sergey wrote: On Thursday, 2 November 2023 at 15:46:23 UTC, confuzzled wrote: I've ported a small script from C to D. The original C version takes roughly 6.5 minutes to parse a 12G file while the port originally took about 48 minutes. In my experience I/O in D is quite slow. But you can try to improve it: Try to use std.outbuffer instead of writeln. And flush the result only in the end. Unless I did it incorrectly, this did nothing for me. My understanding is that I should first prepare an OutBuffer to which I write all my output. Once complete, I then write the OutBuffer to file; which still requires the use of writeln, albeit not as often. First I tried buffering the entire thing, but that turned out to be a big mistake. Next I tried writing and clearing the buffer every 100_000 records (about 3000 writeln calls). Not as bad as the first attempt but significantly worse than what I obtained with the fopen/fprintf combo. I even tried writing the buffer to disk with fprintf but jumped ship because it took far longer than fopen/fprintf. Can't say how much longer because I terminated execution at 14 minutes. Also check this article. It is showing how manual buffers in D could speed up the processing of files significantly: https://tech.nextroll.com/blog/data/2014/11/17/d-is-for-data-science.html The link above was quite helpful. Thanks. I am a bit slow on the uptake so it took a while to figure out how to apply the idea to my own use case. However, once I figured it out, the result was 2 minutes faster than the original C implementation and 3 minutes faster than the fopen/printf port. Whether it did anything for the writeln implementation or not, I don't know. Wasn't will to wait 45+ minutes for something that can feasibly be done in 6 minutes. I gave up at 12. Haven't played with std.string.representation as suggested by Julian as yet but I plan to. Thank again. --Confuzzled
Re: What are the best available D (not C) File input/output options?
On Thursday, 2 November 2023 at 15:46:23 UTC, confuzzled wrote: I've ported a small script from C to D. The original C version takes roughly 6.5 minutes to parse a 12G file while the port originally took about 48 minutes. In my experience I/O in D is quite slow. But you can try to improve it: Try to use std.outbuffer instead of writeln. And flush the result only in the end. Also check this article. It is showing how manual buffers in D could speed up the processing of files significantly: https://tech.nextroll.com/blog/data/2014/11/17/d-is-for-data-science.html
Re: What are the best available D (not C) File input/output options?
On Thursday, 2 November 2023 at 15:46:23 UTC, confuzzled wrote: I tried std.io but write() only outputs ubyte[] while I'm trying to output text so I abandoned idea early. Just specifically to answer this, this is so you understand this is what is going into the file -- bytes. You should use a buffering library like iopipe to write properly here (it handles the encoding of text for you). And I really don't have a good formatting library, you can rely on formattedWrite maybe. A lot of things need to be better for this solution to be smooth, it's one of the things I have to work on. -Steve
Re: What are the best available D (not C) File input/output options?
On Thursday, 2 November 2023 at 15:46:23 UTC, confuzzled wrote: I've ported a small script from C to D. The original C version takes roughly 6.5 minutes to parse a 12G file while the port originally took about 48 minutes. My naïve attempt to improve the situation pushed it over an hour and 15 minutes. However, replacing std.stdio:File with core.stdc.stdio:FILE* and changing my output code in this latest version from: outputFile.writefln("%c\t%u\t%u\t%d.%09u\t%c", ...) to fprintf(outputFile, "%c,%u,%u,%llu.%09llu,%c\n", ...) reduced the processing time to roughly 7.5 minutes. Why is File.writefln() so appallingly slow? Is there a better D alternative? First, strace your program. The slowest thing about I/O is the syscall itself. If the D program does more syscalls, it's going to be slower almost no matter what else is going on. Both D and C are using libc to buffer I/O to reduce syscalls, but you might be defeating that by constantly flushing the buffer. I tried std.io but write() only outputs ubyte[] while I'm trying to output text so I abandoned idea early. string -> immutable(ubyte)[]: alias with std.string.representation(st) 'alias' meaning, this doesn't allocate. If gives you a byte slice of the same memory the string is using. You'd still need to do the formatting, before writing. Now that I've got the program execution time within an acceptable range, I tried replacing core.stdc.fread() with std.io.read() but that increased the time to 24 minutes. Now I'm starting to think there is something seriously wrong with my understanding of how to use D correctly because there's no way D's input/output capabilities can suck so bad in comparison to C's.
What are the best available D (not C) File input/output options?
I've ported a small script from C to D. The original C version takes roughly 6.5 minutes to parse a 12G file while the port originally took about 48 minutes. My naïve attempt to improve the situation pushed it over an hour and 15 minutes. However, replacing std.stdio:File with core.stdc.stdio:FILE* and changing my output code in this latest version from: outputFile.writefln("%c\t%u\t%u\t%d.%09u\t%c", ...) to fprintf(outputFile, "%c,%u,%u,%llu.%09llu,%c\n", ...) reduced the processing time to roughly 7.5 minutes. Why is File.writefln() so appallingly slow? Is there a better D alternative? I tried std.io but write() only outputs ubyte[] while I'm trying to output text so I abandoned idea early. Now that I've got the program execution time within an acceptable range, I tried replacing core.stdc.fread() with std.io.read() but that increased the time to 24 minutes. Now I'm starting to think there is something seriously wrong with my understanding of how to use D correctly because there's no way D's input/output capabilities can suck so bad in comparison to C's.
Re: What is a dchar ?
On Wednesday, 26 July 2023 at 01:56:28 UTC, Richard (Rikki) Andrew Cattermole wrote: The spec says they are unsigned, so if ldc is using sign extension, that is probably a bug. My fault, I reread the code and the sign-extension applies to something else, coincidentally right where I was looking at this. It uses signed 32-bit displacements in a case/switch table of offsets into the code segment, and that was what mislead me. It could have used unsigned displacements but then all the labels in the code would have to be above the reference base point, and this allows +/- offsets to anywhere. So my apologies.
Re: What is a dchar ?
The spec says they are unsigned, so if ldc is using sign extension, that is probably a bug.
Re: what is the aftermath of dip74
On 11/05/2023 6:23 AM, Ferhat Kurtulmuş wrote: Thank you Rikki for the clarification. I think d need this without ugly workarounds. Yeah we do. Reference counting is expensive, and modern backends have the capability to elide pairs of calls. So this would be a massive improvement just from the perspective of performance alone.
Re: what is the aftermath of dip74
On Wednesday, 10 May 2023 at 18:15:36 UTC, Richard (Rikki) Andrew Cattermole wrote: We do not, no. Reference counting is not currently in the language, although you can fake it with structs. Its a huge shame, but it should be added at some point because the compiler would tell the backend that it is possible to elide pair calls. However it'll have to wait for the DIP queue to reopen (slight process adjustment to make things easier is incoming). Thank you Rikki for the clarification. I think d need this without ugly workarounds.
Re: what is the aftermath of dip74
We do not, no. Reference counting is not currently in the language, although you can fake it with structs. Its a huge shame, but it should be added at some point because the compiler would tell the backend that it is possible to elide pair calls. However it'll have to wait for the DIP queue to reopen (slight process adjustment to make things easier is incoming).
Re: What do you think about using Chat GPT to create functions in D?
On Monday, 3 April 2023 at 23:38:52 UTC, Marcone wrote: What do you think about using Chat GPT to create functions in D? I asked Chat-GPT to create a function in D that was similar to the rsplit() function in Python. It returned this code to me: import std.algorithm; import std.array; import std.string; string[] rsplit(string input, string separator, size_t maxsplit = size_t.max) { auto splitter = splitter(input, separator, SplitterFlag.all); auto results = splitter.array; if (maxsplit < results.length - 1) results = results[results.length - maxsplit - 1 .. $]; return results; } Recently, it helped me figure out an OpenGL task using d. This is the code it suggests after I provide some details to it about the case and the error I get: ```d Slice!(RCI!ubyte, 3LU, Contiguous) plot2imslice() @nogc nothrow { import mir.rc; Slice!(RCI!ubyte, 3LU, Contiguous) imgslice = rcslice!ubyte([height, width, 3], 0); glfwMakeContextCurrent(_glfwWindow); // create and bind framebuffer GLuint fbo; glGenFramebuffers(1, ); glBindFramebuffer(GL_FRAMEBUFFER, fbo); // create and bind texture GLuint texture; glGenTextures(1, ); glBindTexture(GL_TEXTURE_2D, texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, null); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); // render scene to framebuffer glBindFramebuffer(GL_FRAMEBUFFER, fbo); // render your scene here // read pixel data from framebuffer glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, imgslice.ptr); // flip image vertically for (size_t y = 0; y < height / 2; y++) { for (size_t x = 0; x < width; x++) { // swap rows swap(imgslice[y][x], imgslice[height - y - 1][x]); } } // unbind framebuffer and cleanup glBindFramebuffer(GL_FRAMEBUFFER, 0); glDeleteTextures(1, ); glDeleteFramebuffers(1, ); return imgslice; } ``` And this is the code after required modifications: ```d auto plot2imslice() @nogc nothrow { import mir.rc; Slice!(RCI!ubyte, 3LU, Contiguous) imgslice = rcslice!ubyte([height, width, 3], 0); glfwMakeContextCurrent(_glfwWindow); // create and bind framebuffer GLuint fbo; glGenFramebuffers(1, ); glBindFramebuffer(GL_FRAMEBUFFER, fbo); // create and bind texture GLuint texture; glGenTextures(1, ); glBindTexture(GL_TEXTURE_2D, texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, null); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); // render scene to framebuffer glBindFramebuffer(GL_FRAMEBUFFER, fbo); // render scene here render(); // read pixel data from framebuffer glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, imgslice.ptr); import mir.utility : swap; // flip image vertically to correct generated image foreach (y; 0..height / 2) { each!swap(imgslice[y], imgslice[height - y - 1]); } // unbind framebuffer and cleanup glBindFramebuffer(GL_FRAMEBUFFER, 0); glDeleteTextures(1, ); glDeleteFramebuffers(1, ); return imgslice; } ``` This comment of chatGPT saved the day :) // render your scene here
Re: What do you think about using Chat GPT to create functions in D?
On Monday, 3 April 2023 at 23:38:52 UTC, Marcone wrote: What do you think about using Chat GPT to create functions in D? Well you can use GitHub Copilot in VSCode, and it is kind of interesting but at the current time seems like a distracting waste of time. It will probably get more useful in a few years. LLMs repeats commonly accepted lies as gospel, so do not expect a well adjusted human-like opinion on anything.
Re: What do you think about using Chat GPT to create functions in D?
I once tested ChatGPT to generate Common Lisp code (a simple Redis client). They had a warning that this is not a code generation tool nevertheless it tried to do so. All the code it had was incorrect: it imported foreign libraries that didn't exist and when I complained about it, it apologized and then proposed other libraries that didn't exist. Overall I had the impression that I'm working with some dumb person who pasted me stuff from stackoverflow that seemed to solve my issue. Let me mention that I once asked ChatGPT what is 11 plus 11 and when it responded 22, I told it that it's wrong, it should be 30. It apologized and said that I'm right, it's 30. I tried to do the same experiment again after one day to show off my friends, but it became more resilient to such suggestions.
What do you think about using Chat GPT to create functions in D?
What do you think about using Chat GPT to create functions in D? I asked Chat-GPT to create a function in D that was similar to the rsplit() function in Python. It returned this code to me: import std.algorithm; import std.array; import std.string; string[] rsplit(string input, string separator, size_t maxsplit = size_t.max) { auto splitter = splitter(input, separator, SplitterFlag.all); auto results = splitter.array; if (maxsplit < results.length - 1) results = results[results.length - maxsplit - 1 .. $]; return results; }
Re: what is the difference between AliasAssign and AliasReassignment
On Monday, 27 March 2023 at 16:59:29 UTC, FabArd wrote: Hi, I don't understand a point in the grammar : 5.4.6 AliasAssign: Identifier = Type 5.4.7 AliasReassignment: Identifier = StorageClasses(optional) Type AliasAssign rule is included in the AliasReassignment rule. Why there are two rules in the grammar to describe the same thing? It seems that AliasReassignment rule is an orphan rule. Indeed it is not used anywhere else in the whole grammar.
what is the difference between AliasAssign and AliasReassignment
Hi, I don't understand a point in the grammar : 5.4.6 AliasAssign: Identifier = Type 5.4.7 AliasReassignment: Identifier = StorageClasses(optional) Type AliasAssign rule is included in the AliasReassignment rule. Why there are two rules in the grammar to describe the same thing?
Re: What makes vibe.d Incredibly Slow on a VPS?
On 3/18/23 9:36 AM, seany wrote: But on a VPS server, the program outputs the first writeln line (not even the consequent req.form printouts), then apparently stops for several seconds ( 10 to 16) , and then suddenly starts working again. I see this in the log outputs. Why does this happen? How can I start debugging? Before getting into it any further, try flushing output after every writeln. This is true in D and C too -- if your `stdout` stream is connected to a log file, it will *not* flush upon every newline. However, if it's connected to a terminal, it *will* flush upon every newline. It's possible it is running just as fast as you expect, but the buffered output has not yet been flushed. So just add `stdout.flush()` after every `writeln` call and see if it helps. If not, then it needs more investigation. -Steve
What makes vibe.d Incredibly Slow on a VPS?
Consider this fraction of code Please: void createNewOwner(HTTPServerRequest req, HTTPServerResponse res) { writeln("NEW OWNER requests are : -"); writeln(req.form); writeln(req.files); writeln("=="); // TASK EXTRACT the data from the POST variable// --// // TODO check security with req.form["loginToken"]; string avatarPath ; if( req.files.length != 0) { // HERE we only check if file is supplied... // no "existing avatar" yet, as fresh new user. auto file = "file" in req.files; if (file.filename != "" ) { string k = genNonce();// Generate a random number to ensure there is no conflict string rp = req.form["username"].replace(" ", "-").replace("@", "-")~"-"~k~"-"~(file.filename.name).replace(" ", "-").replace("@", "-"); // replaced spaces with "-" and @ with -, to avoid loading problems try { moveFile(file.tempPath.toString(), "assets/images/avatars/" ~ rp); writeln("Uploaded successfully!"); avatarPath = "/" ~ "assets/images/avatars/" ~ rp; } catch (Exception e) { writeln("Exception thrown, trying copy"); copyFile(file.tempPath.toString(), "assets/images/avatars/" ~ rp); avatarPath = "/" ~ "assets/images/avatars/" ~ rp; } } } else { avatarPath = "assets/images/avatars/noFace.png"; // Here it is allowed. IF no image, then set a default. } avatarPath = avatarPath.replace(" ", ""); // should not be needed, but just in case avatarPath = avatarPath.replace("@", "-"); string e2fa = ""; req.form["en2fa"] == "true" ? (e2fa = "1") : (e2fa = "0");// converted e2FA to 0 or 1, in string format // TASK confirm no conclict // --// auto check_existingUser = loginRoutines.get_userAllInfo( req.form["username"]); if (check_existingUser.length != 0) { // username already exists The only valid value here is 0 // = no records. anything != 0 will be rejected res.writeBody("ERROR: 30LX-USEREX. Username existiert schon... Verwenden Sie bitte einen anderen Username."); return; } // TASK set entry details // // int usrCnt = loginRoutines.get_userCount();write("user count is: "); writeln(usrCnt); if (usrCnt < 0) { res.writeBody("ERROR: 71QM-UKNDBR. Unbekannter Datenbankfehler. Versuchen Sie später erneut."); return; } string cntr = to!string(usrCnt +1); // next item in file. string[string] nuInfo ; // container for new user Info nuInfo["username"]= req.form["username"]; nuInfo["fName"] = req.form["fName"]; nuInfo["lName"] = req.form["lName"]; nuInfo["avatarPath"]= avatarPath; nuInfo["mail"]= req.form["mail"]; nuInfo["tel"] = req.form["tel"]; nuInfo["mob"] = req.form["mob"]; string[string] lgInfo; lgInfo["username"]= req.form["username"]; lgInfo["role"]= "owner"; lgInfo["active"] = "-1"; write("going to add signUp line in user dtls : "); writeln(lgInfo); string loginInfo = cntr ~ "," ~ req.form["username"] ~ "," ~ "++" ~ "," ~ e2fa ~ ", 0"; // enter new user with supplied 2FA, but set the last field = 0, // as not yet paired. // TASK insert the data // --// bool stat;write("going to add signUp line in owner dtls : "); writeln(nuInfo); stat =
Re: dub.sdl bindbc-glfw is returning a deprecation warming. So what do I do now?
On Thursday, 9 March 2023 at 06:36:18 UTC, IchorDev wrote: On Thursday, 9 March 2023 at 00:21:02 UTC, WhatMeWorry wrote: [...] Sorry about that. Try updating to bindbc-glfw 1.0.2, should be fixed now. If you see any other deprecation warnings from BindBC bindings you can silence them with `-d` until they're updated. No problem :) Thanks!
Re: dub.sdl bindbc-glfw is returning a deprecation warming. So what do I do now?
On Thursday, 9 March 2023 at 00:21:02 UTC, WhatMeWorry wrote: my small dub.sdl project uses: dependency "bindbc-glfw" version="~>1.0.1" versions "GLFW_33" and returns Building bindbc-glfw 1.0.1: building configuration [dynamic] C:\Users\Admin\AppData\Local\dub\packages\bindbc-glfw-1.0.1\bindbc-glfw\source\bindbc\glfw\binddynamic.d(557,11): Deprecation: variable `bindbc.loader.system.bindWindows` is deprecated So now what? I'm pretty sure deprecation means to replace with something better but what would that be? I looked on github code in binddynamic.d at line 557 and the package info at the DUB web site and I'm still clueless. Sorry about that. Try updating to bindbc-glfw 1.0.2, should be fixed now. If you see any other deprecation warnings from BindBC bindings you can silence them with `-d` until they're updated.
Re: dub.sdl bindbc-glfw is returning a deprecation warming. So what do I do now?
On 3/8/23 7:21 PM, WhatMeWorry wrote: my small dub.sdl project uses: dependency "bindbc-glfw" version="~>1.0.1" versions "GLFW_33" and returns Building bindbc-glfw 1.0.1: building configuration [dynamic] C:\Users\Admin\AppData\Local\dub\packages\bindbc-glfw-1.0.1\bindbc-glfw\source\bindbc\glfw\binddynamic.d(557,11): Deprecation: variable `bindbc.loader.system.bindWindows` is deprecated So now what? I'm pretty sure deprecation means to replace with something better but what would that be? I looked on github code in binddynamic.d at line 557 and the package info at the DUB web site and I'm still clueless. It's newly deprecated, without much explanation: https://github.com/BindBC/bindbc-loader/commit/d13d7f246f325472b26282cfac8d2b02b26eccac Last commit to bindbc-glfw is from last year, so it makes sense why it is triggering this. I feel it was in error to deprecate symbols without bumping the major revision. -Steve
dub.sdl bindbc-glfw is returning a deprecation warming. So what do I do now?
my small dub.sdl project uses: dependency "bindbc-glfw" version="~>1.0.1" versions "GLFW_33" and returns Building bindbc-glfw 1.0.1: building configuration [dynamic] C:\Users\Admin\AppData\Local\dub\packages\bindbc-glfw-1.0.1\bindbc-glfw\source\bindbc\glfw\binddynamic.d(557,11): Deprecation: variable `bindbc.loader.system.bindWindows` is deprecated So now what? I'm pretty sure deprecation means to replace with something better but what would that be? I looked on github code in binddynamic.d at line 557 and the package info at the DUB web site and I'm still clueless.
Re: What is the 'Result' type even for?
On Fri, Jan 20, 2023 at 12:49:54PM +, Ruby The Roobster via Digitalmars-d-learn wrote: [...] > Thank you. I didn't know that there was such a property `.array`. It's not a property, it's a Phobos function from std.array. T -- INTEL = Only half of "intelligence".
Re: What is the 'Result' type even for?
On Friday, 20 January 2023 at 03:39:48 UTC, H. S. Teoh wrote: On Fri, Jan 20, 2023 at 03:34:43AM +, Ruby The Roobster via Digitalmars-d-learn wrote: On Friday, 20 January 2023 at 03:30:56 UTC, Steven Schveighoffer wrote: > On 1/19/23 10:11 PM, Ruby The Roobster wrote: > ... > > The point is to be a range over the original input, > evaluated lazily. Using this building block, you can create > an array, or use some other algorithm, or whatever you want. > All without allocating more space to hold an array. [...] I get the point that it is supposed to be lazy. But why are these basic cases not implemented? I shouldn't have to go write a wrapper for something as simple as casting this type to the original type. This is one of the things that one expects the standard library to do for you. There's no need to write any wrappers. Just tack `.array` to the end of your pipeline, and you're good to go. T Thank you. I didn't know that there was such a property `.array`.
Re: What is the 'Result' type even for?
On Friday, 20 January 2023 at 04:46:07 UTC, Ali Çehreli wrote: Different instantiations of templates are distinct types. For example, if I called 'alternate' with two 'long' values, both alternate!int (as instantiated by the code above) and alternate!long would have different MyResult struct types. In general, the ranges are compatible with each other because they use the empty, front, popFront interface. In the example below, different types (one of which is double) but the same ranges can be combined with chain(). However, it is necessary to convert it to array because of the opCmp() compatibility from algorithms such as sorting. ```d import std.algorithm : sort; import std.conv : to; import std.range; import std.stdio; enum limit = 5; enum step = limit / 10.0;/* enum step = 1; //*/ void main() { TypeInfo rangeType; auto a = iota(limit); auto b = iota(step, limit, step); /* <- toggle comment, please add -> / auto ab = chain(a, b); rangeType = typeid(ab);/*/ auto arrA = a.array.to!(double[]); auto arrB = b.array; auto ab = chain(arrA, arrB); rangeType = typeid(ab.sort);//*/ ab.writeln(": ", rangeType); } /* current print: == [0, 0.5, 1, 1, 1.5, 2, 2, 2.5, 3, 3, 3.5, 4, 4, 4.5]: std.range.SortedRange!(std.range.chain!(double[], double[]).chain(double[], double[]).Result, "a < b", 0).SortedRange other print: [0, 1, 2, 3, 4, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5]: std.range.chain!(std.range.iota!(int, int).iota(int, int).Result, std.range.iota!(double, int, double).iota(double, int, double).Result).chain(std.range.iota!(int, int).iota(int, int).Result, std.range.iota!(double, int, double).iota(double, int, double).Result).Result ``` SDB@79
Re: What is the 'Result' type even for?
On 1/19/23 19:11, Ruby The Roobster wrote: > typeof(c).stringof.writeln; > The program prints: > > ["a", "b", "c", "d", "e"] > Result > > What is the purpose of this 'Result' type? Just to make sure, 'Result' is what the programmer of a Phobos algorithm chose to name a struct type. It could be anything. I will try to demonstrate it by naming my struct 'MyResult' below. The following range algorithm alternates between the two values it is called with. The pragma(msg) inside 'main' prints MyResult. auto alternate(T)(T a, T b) { // This function will return an object // of the following nested struct. // (Note: This is for demonsration // purposes only. Yes, this can be // be more optimal.) struct MyResult { bool useB = false; enum empty = false; // Infinite T front() { return useB ? b : a; } void popFront() { // Flip the selector useB = !useB; } } // Here, an object of the struct is // returned. It has single member (useB) // that it uses as a selector. // The values 'a' and 'b' are the actual // function arguments. return MyResult(); } import std; void main() { auto myRange = alternate(42, 7); // This prints 'MyResult' at compile time pragma(msg, typeof(myRange)); const expected = [ 42, 7, 42, 7, 42 ]; assert(myRange.take(5).equal(expected)); } > even when the type > has the same inherent function: Different instantiations of templates are distinct types. For example, if I called 'alternate' with two 'long' values, both alternate!int (as instantiated by the code above) and alternate!long would have different MyResult struct types. Although they would have the same functionality, they would be compiled potentially with very different CPU instructions and would not be assignable. Ali
Re: What is the 'Result' type even for?
On Friday, 20 January 2023 at 03:11:33 UTC, Ruby The Roobster wrote: What is the purpose of this 'Result' type? To serve as a generic range? Because, it seems to only cause problems... No. When I first started learning this language, I thought the same thing. However, such a designm consisting of structs was preferred because it is necessary for the ranges to be used as a whole (connected end-to-Znd like a pipe). qWalter has a very old [article](https://www.drdobbs.com/cpp/voldemort-types-in-d/232901591) about Voldemort which is the basis of D, pllease read it. D's ranges are very strong for those who know how to use it. SDB@79
Re: What is the 'Result' type even for?
On Friday, 20 January 2023 at 03:11:33 UTC, Ruby The Roobster wrote: Take this example: [...] What is the purpose of this 'Result' type? To serve as a generic range? Yes this is a lazy input range. Use `.array` to yield directly as a concrete value, then you can append using `~=`. Note that there are special functions to keep the laziness, e.g `chain` to happen an input range to another element-compatible input range ``` import std; void main() { auto c = "a|b|c|d|e".splitter("|").chain(["f"]); string[] e = ["a", "b", "c", "d", "e", "f"]; assert(c.equal(e)); } ```
Re: What is the 'Result' type even for?
On 1/19/23 10:34 PM, Ruby The Roobster wrote: On Friday, 20 January 2023 at 03:30:56 UTC, Steven Schveighoffer wrote: On 1/19/23 10:11 PM, Ruby The Roobster wrote: ... The point is to be a range over the original input, evaluated lazily. Using this building block, you can create an array, or use some other algorithm, or whatever you want. All without allocating more space to hold an array. I get the point that it is supposed to be lazy. But why are these basic cases not implemented? I shouldn't have to go write a wrapper for something as simple as casting this type to the original type. This is one of the things that one expects the standard library to do for you. A range simply does not provide the API you are seeking. It provides 3 methods: front popFront empty That's it. It does not provide appending. If you want appending or random access, use an array: ```d auto c = "a|b|c|d|e".split('|'); static assert(is(typeof(c) == string[])); // or: auto c2 = "a|b|c|d|e".splitter('|').array; // convert range to an array ``` -Steve
Re: What is the 'Result' type even for?
On Fri, Jan 20, 2023 at 03:34:43AM +, Ruby The Roobster via Digitalmars-d-learn wrote: > On Friday, 20 January 2023 at 03:30:56 UTC, Steven Schveighoffer wrote: > > On 1/19/23 10:11 PM, Ruby The Roobster wrote: > > ... > > > > The point is to be a range over the original input, evaluated > > lazily. Using this building block, you can create an array, or use > > some other algorithm, or whatever you want. All without allocating > > more space to hold an array. [...] > I get the point that it is supposed to be lazy. But why are these > basic cases not implemented? I shouldn't have to go write a wrapper > for something as simple as casting this type to the original type. > This is one of the things that one expects the standard library to do > for you. There's no need to write any wrappers. Just tack `.array` to the end of your pipeline, and you're good to go. T -- My father told me I wasn't at all afraid of hard work. I could lie down right next to it and go to sleep. -- Walter Bright
Re: What is the 'Result' type even for?
On Friday, 20 January 2023 at 03:30:56 UTC, Steven Schveighoffer wrote: On 1/19/23 10:11 PM, Ruby The Roobster wrote: ... The point is to be a range over the original input, evaluated lazily. Using this building block, you can create an array, or use some other algorithm, or whatever you want. All without allocating more space to hold an array. -Steve I get the point that it is supposed to be lazy. But why are these basic cases not implemented? I shouldn't have to go write a wrapper for something as simple as casting this type to the original type. This is one of the things that one expects the standard library to do for you.
Re: What is the 'Result' type even for?
On Fri, Jan 20, 2023 at 03:11:33AM +, Ruby The Roobster via Digitalmars-d-learn wrote: > Take this example: > > ```d > import std; > void main() > { > auto c = "a|b|c|d|e".splitter('|'); > c.writeln; > string[] e = ["a", "b", "c", "d", "e"]; > assert(c.equal(e)); > typeof(c).stringof.writeln; > } > ``` > > The program prints: > > ["a", "b", "c", "d", "e"] > Result > > What is the purpose of this 'Result' type? To serve as a generic > range? It's a Voldemort type, representing a range that iterates over its elements lazily. > Because, it seems to only cause problems. For example, you cannot > assign or cast the result type into a range, even when the type has > the same inherent function: > > ```d > string[] c = "a|b|c|d|e".splitter('|'); // fails > string[] d = cast(string[])"a|b|c|d|e".splitter('|'); // also fails > ``` You're confusing arrays and ranges. A "range" isn't any specific type, it refers to *any* type that behaves a certain way (behaves like a range). Each `Result` you get back has its own unique type (arguably, it's a compiler bug to display it as merely `Result` without distinguishing it from other identically-named but distinct Voldemort types), so you cannot just assign it back to an array. You can either create an array from it using std.array.array, use a function that eagerly creates its results instead of a lazy result (in the above instance, use std.string.split instead of .splitter), or use std.algorithm.copy to copy the contents of the lazy range into an array: // Option 1 string[] c = "a|b|c|d|e".splitter('|').dup; // Option 2 string[] c = "a|b|c|d|e".split('|'); // Option 3 // Caveat: .copy expects you to have prepared the buffer // beforehand to be large enough to hold the contents; it does // not reallocate the result array for you. string[] result = new string[5]; "a|b|c|d|e".splitter('|').copy(result); [...] > Then what is the point of this type, if not to just make things > difficult? It cannot be casted, and vector operations cannot be > performed, and it seems to just serve as an unnecessary > generalization. It serves to chain further range operations into a pipeline: string[] c = "a|b|c|d|e".splitter('|') .filter!(c => c >= 'b' && c <= 'd') .map!(c => c+1) .array; Because ranges are lazily iterated, the .array line only allocates the 3 elements that got through the .filter. Whereas if you created the intermediate result array eagerly, you'd have to allocate space for 5 elements only to discard 2 of them afterwards. One way to think about this is that the intermediate Result ranges are like the middle part of a long pipe; you cannot get stuff from the middle of the pipe without breaking it, you need to terminate the pipe with a sink (like .array, .copy, etc.) first. T -- I am Pentium of Borg. Division is futile; you will be approximated.
Re: What is the 'Result' type even for?
On 1/19/23 10:11 PM, Ruby The Roobster wrote: Take this example: ```d import std; void main() { auto c = "a|b|c|d|e".splitter('|'); c.writeln; string[] e = ["a", "b", "c", "d", "e"]; assert(c.equal(e)); typeof(c).stringof.writeln; } ``` The program prints: ["a", "b", "c", "d", "e"] Result What is the purpose of this 'Result' type? To serve as a generic range? Because, it seems to only cause problems. For example, you cannot assign or cast the result type into a range, even when the type has the same inherent function: ```d string[] c = "a|b|c|d|e".splitter('|'); // fails string[] d = cast(string[])"a|b|c|d|e".splitter('|'); // also fails ``` The `Result` type is an internal type that provides a lazily-evaluated range of the original string. That is, no array is allocated, and the actual searching of the `|` character isn't done until you start fetching each element. It returns windows into the *original* string, and builds each window one element at a time (via slicing). So when you say "cast to a range", you are incorrectly stating the type `string[]` as a "range", when you are trying to cast to an array of strings. The `Result` type *is* a range, it's a range of strings. But it is not an array. If you want an array, you can use the `split` function, which allocates an array to hold all the slices. And if you need to perform a set operation? ```d c[] ~= "lolno"; // fails, as [] isn't defined for Result. ``` Right, because a `Result` is not an array. Appending is an array operation, not a range operation. Then what is the point of this type, if not to just make things difficult? It cannot be casted, and vector operations cannot be performed, and it seems to just serve as an unnecessary generalization. The point is to be a range over the original input, evaluated lazily. Using this building block, you can create an array, or use some other algorithm, or whatever you want. All without allocating more space to hold an array. -Steve
Re: What is the 'Result' type even for?
On Friday, 20 January 2023 at 03:11:33 UTC, Ruby The Roobster wrote: Take this example: ```d import std; void main() { auto c = "a|b|c|d|e".splitter('|'); c.writeln; string[] e = ["a", "b", "c", "d", "e"]; assert(c.equal(e)); typeof(c).stringof.writeln; } ``` The program prints: ["a", "b", "c", "d", "e"] Result What is the purpose of this 'Result' type? To serve as a generic range? Because, it seems to only cause problems. For example, you cannot assign or cast the result type into a range, even when the type has the same inherent function: ```d string[] c = "a|b|c|d|e".splitter('|'); // fails string[] d = cast(string[])"a|b|c|d|e".splitter('|'); // also fails ``` And if you need to perform a set operation? ```d c[] ~= "lolno"; // fails, as [] isn't defined for Result. ``` Then what is the point of this type, if not to just make things difficult? It cannot be casted, and vector operations cannot be performed, and it seems to just serve as an unnecessary generalization. Furthermore, it can also be confirmed that each member of c is a string, further solidifying my opinion of 'Result' as just being a generic range template, that cannot be casted to an array of the original type.
What is the 'Result' type even for?
Take this example: ```d import std; void main() { auto c = "a|b|c|d|e".splitter('|'); c.writeln; string[] e = ["a", "b", "c", "d", "e"]; assert(c.equal(e)); typeof(c).stringof.writeln; } ``` The program prints: ["a", "b", "c", "d", "e"] Result What is the purpose of this 'Result' type? To serve as a generic range? Because, it seems to only cause problems. For example, you cannot assign or cast the result type into a range, even when the type has the same inherent function: ```d string[] c = "a|b|c|d|e".splitter('|'); // fails string[] d = cast(string[])"a|b|c|d|e".splitter('|'); // also fails ``` And if you need to perform a set operation? ```d c[] ~= "lolno"; // fails, as [] isn't defined for Result. ``` Then what is the point of this type, if not to just make things difficult? It cannot be casted, and vector operations cannot be performed, and it seems to just serve as an unnecessary generalization.
Re: what wrong with this alias
On 1/8/23 12:42 AM, Qusatlegadus wrote: auto s = 1234.to!string.map!q{a - '0'}.sum; works fine. but if i do an alias alias comb = to!string.map!q{a - '0'} Error: unknown, please file report on issues.dlang.org What's wrong with this alias? Aside from the problem with the code, that error alone deserves a bug report so... https://issues.dlang.org/show_bug.cgi?id=23615 -Steve
Re: what wrong with this alias
On Sunday, 8 January 2023 at 09:45:09 UTC, Krzysztof Jajeśnica wrote: ## Simple explanation `to!string` is a function expecting 1 argument, which you're not providing in your alias. Convert your alias to a lambda expression: ```D alias comb = x => x.to!string.map!q{a - '0'} ``` A logical solution... Since your goal is to manipulate numbers, it is possible to convert directly to char type: ```d import std.algorithm : map, sum; import std.conv : toChars; alias comb = (uint x) => x.toChars.map!"a - '0'"; void main() { auto s = 2234.comb.sum; assert(s.comb.sum == 2); } ``` SDB@79
Re: what wrong with this alias
On Sunday, 8 January 2023 at 05:42:46 UTC, Qusatlegadus wrote: auto s = 1234.to!string.map!q{a - '0'}.sum; works fine. but if i do an alias alias comb = to!string.map!q{a - '0'} Error: unknown, please file report on issues.dlang.org What's wrong with this ## Simple explanation `to!string` is a function expecting 1 argument, which you're not providing in your alias. Convert your alias to a lambda expression: ```D alias comb = x => x.to!string.map!q{a - '0'} ``` ## Complicated explanation `to` is a template defined like this: ```D // https://github.com/dlang/phobos/blob/master/std/conv.d template to(T) { T to(A...)(A args) if (A.length > 0) { return toImpl!T(args); } // some overloads omitted for brevity } ``` `to` needs at least 2 template arguments - the first one for the outer template is passed explicitly (what you did with `to!string`), the other ones are inferred from the arguments passed to the `to` function. Since you did not pass an argument to `to!string`, the inner template doesn't get instantiated. Basically what happens is you're trying to pass an uninstantiated template as argument to `map`. This is quite an exotic situation, so probably there isn't a dedicated error message for it or you're hitting a bug in the compiler (hence the unknown error message).
Re: what wrong with this alias
On Sunday, 8 January 2023 at 05:42:46 UTC, Qusatlegadus wrote: What's wrong with this alias? ```d import std; alias comb = map!q{a - '0'}; void main() { auto s = 2234.to!string.map!q{a - '0'}.sum; s.to!string.comb.sum.writeln; // thiS works: "2" } ``` SDB@79
what wrong with this alias
auto s = 1234.to!string.map!q{a - '0'}.sum; works fine. but if i do an alias alias comb = to!string.map!q{a - '0'} Error: unknown, please file report on issues.dlang.org What's wrong with this alias?
Re: Compile time vs run time -- what is the difference?
On Sun, Jan 01, 2023 at 02:18:23AM +, Salih Dincer via Digitalmars-d-learn wrote: > On Sunday, 1 January 2023 at 01:20:02 UTC, Ali Çehreli wrote: > > On 12/31/22 16:42, H. S. Teoh wrote: > > > > - runtime: The D runtime. > > Sometimes I see runtime facilities used as compile time and I'm having > a hard time distinguishing that. It is even possible to use it with > meta-programming facilities. [...] > Do you have a solid recommendation about distinguishing? [...] https://wiki.dlang.org/Compile-time_vs._compile-time ;-) T -- MACINTOSH: Most Applications Crash, If Not, The Operating System Hangs
Re: Compile time vs run time -- what is the difference?
On Sunday, 1 January 2023 at 01:20:02 UTC, Ali Çehreli wrote: On 12/31/22 16:42, H. S. Teoh wrote: - runtime: The D runtime. Sometimes I see runtime facilities used as compile time and I'm having a hard time distinguishing that. It is even possible to use it with meta-programming facilities. It is a powerful feature that can help to improve the expressiveness and efficiency of D programs, but it can also make code more difficult to understand and maintain. Do you have a solid recommendation about distinguishing? SDB@79
Re: Compile time vs run time -- what is the difference?
On 12/31/22 16:42, H. S. Teoh wrote: > "runtime" Going off topic, I've settled on three different spelling of that (those? :) ): - run time: As in this topic, things can happen at run time. - run-time: Adjective, as in run-time value of something. - runtime: The D runtime. Ali
Re: Compile time vs run time -- what is the difference?
On Wed, Dec 28, 2022 at 02:31:45AM +, thebluepandabear via Digitalmars-d-learn wrote: > I am reading through the free book on learning D by Ali Çehreli and I > am having difficulties understanding the difference between compile > time execution and run time execution in D language. It's very simple: in a compiled language like D, your program goes through 3 stages: 1) Source code: the human-readable text that you write. 2) Compilation: this is when the compiler is compiling your program. IOW, "compile time". Compile time happens once when you compile your program. 3) Binary executable: the result of compilation. When you run this executable, that's "runtime". Runtime happens every time you run the program. Stage (2) is transient, and only happens inside the compiler. It can be broken down into several steps: a) Lexing & parsing: the compiler reads the source code, breaks it into tokens (keywords, identifiers, operators, etc.), and constructs from them an abstract syntax tree (AST) that represents your program. Here is where typos and syntax errors are detected. b) Semantic analysis: the compiler processes the AST and assigns meaning to each corresponding programming construct. Here is where (some) logic errors are detected (reference to an undefined identifier, invalid operations on a data type, calling a function with the wrong number of arguments, etc.). c) Code generation: based on the semantics the compiler assigned to your program, it emits a series of CPU instructions that implement these semantics. These instructions are generally saved into either intermediate object files that must later be linked together, or directly into the final executable. D's compile-time capabilities are mainly of two categories: i) AST manipulation: templates, static if, static foreach, and pragma(msg) belong to this category. This generally happens between steps (a) and (b). ii) CTFE (compile-time function evaluation): this happens somewhere around step (c), and mainly consists of the compiler interpreting part of the program using an internal interpreter in order to compute the value of a function at compile-time. This is triggered when this value is required in order to resolve something that's needed during compilation. For more details, see: https://wiki.dlang.org/Compile-time_vs._compile-time T -- If you think you are too small to make a difference, try sleeping in a closed room with a mosquito. -- Jan van Steenbergen
Re: Compile time vs run time -- what is the difference?
On Wednesday, 28 December 2022 at 12:42:24 UTC, thebluepandabear wrote: Before even running the code I get an IDE warning (IntelliJ). Does IntelliJ compile the code in the background? It will NOT compile successfully unless you do one of these things: (1) ensure the result of the 'static assert' is true. (2) comment out the static assert. Once you do either of (1) or (2) above, it will compile to an executable format. When you execute it, the runtime will catch the 'assert' failure (ie. assertion == false), and the runtime will bring your program to an immediate halt. This was just meant to be an example of differentiating compile time from runtime, as per you question. With static assert, your logic testing is traversed during compilation, and your compilation will come to a stop when the assertion is found to be false, whereas your asserts are traversed during program execution, and if they are found to be false, your program comes to a stop. https://dlang.org/spec/version.html#static-assert https://tour.dlang.org/tour/en/gems/contract-programming
Re: Compile time vs run time -- what is the difference?
On 12/28/22 08:04, Ali Çehreli wrote: > I don't think any of them can run the program though because > the program can be in a state that could harm its environment > like deleting unwanted files. I was too eager there. Likely no IDE goes that far. All they need is to understand the code enough to give help. They must stop at some point in the following steps of compilation: - preprocessing (does not exist for D) - lexical analysis - parsing - semantic analysis I copied those items from Wikipedia: https://en.wikipedia.org/wiki/Compiler It lists the later stages of compilation as - intermediate representation - code optimization - code generation Ali
Re: Compile time vs run time -- what is the difference?
On 12/27/22 18:31, thebluepandabear wrote: > What I do understand is that compile time and run time are the two > processes that your code goes through to be executed natively. There is a confusion: Compile time ends when the compiler generates the executable program, one that will be executed natively. Run time is each time when the user starts the executable program by typing its name followed by the Enter key, double clicking on it, etc. For a program that was extremely simple, bug-free, lucky, etc. there may be as few as a single compilation and infinite number of executions (run times). On the other hand, for a program that could never be compiled successfully, there may be infinite number of compilations and zero run times. > In Java and some other languages, during compile time the code gets > executed into Java bytecode. This also happens for C#. I don't know if > there is an equivalent 'intermediate' language for D that your code gets > translated to. No, D does not use that model. Copying a comment of yours: > Before even running the code I get an IDE warning > (IntelliJ). Does IntelliJ compile the code in the background? Yes, many IDEs continuously compile the code as you type the source code to understand it to give you such help. I don't think any of them can run the program though because the program can be in a state that could harm its environment like deleting unwanted files. Ali
Re: Compile time vs run time -- what is the difference?
On Wednesday, 28 December 2022 at 09:10:38 UTC, areYouSureAboutThat wrote: On Wednesday, 28 December 2022 at 02:31:45 UTC, thebluepandabear wrote: .. Other errors are only able to be spotted during run time such as exceptions, dividing by zero, assert blocks. With regards to the 'assert blocks' you mention, D (like C++) has both static assert and runtime assert. // --- module test; @safe: import std; void main() { string val = "some string"; static assert(is(typeof(x) : int)); // assertion fails at compile time. assert(val == "some other string"); // assertion fails at runtime. } // --- Before even running the code I get an IDE warning (IntelliJ). Does IntelliJ compile the code in the background?
Re: Compile time vs run time -- what is the difference?
On Wednesday, 28 December 2022 at 02:31:45 UTC, thebluepandabear wrote: .. Other errors are only able to be spotted during run time such as exceptions, dividing by zero, assert blocks. With regards to the 'assert blocks' you mention, D (like C++) has both static assert and runtime assert. // --- module test; @safe: import std; void main() { string val = "some string"; static assert(is(typeof(x) : int)); // assertion fails at compile time. assert(val == "some other string"); // assertion fails at runtime. } // ---
Re: Compile time vs run time -- what is the difference?
On Wednesday, 28 December 2022 at 02:31:45 UTC, thebluepandabear wrote: In Java and some other languages, during compile time the code gets executed into Java bytecode. This also happens for C#. I don't know if there is an equivalent 'intermediate' language for D that your code gets translated to. With statically compiled languages like D, C, and C++, the compiler ultimately translates your source code to what's referred to as "machine code". Compilers output object files, which are in turn linked into an executable file by a linker. Static compilers can use intermediate representations like Java bytecode. For example, compilation could consist of two steps handled by two different programs, one that translates the source to bytecode, and one that translates the bytecode to an object file. This is how LLVM-based compilers like Clang and LDC work. Clang translates C source to LLVM IR (Intermediate Representation). LDC translated C source to LLVM IR. Both pass the generated IR to the LLVM compiler, which outputs the object files that are then given to a linker. Static Java compilers do the same thing with Java bytecode. Java JIT compilers built into Java VMs translate Java bytecode to machine code while the program is running. So compilation is just the act of translating from one source format to another (e.g., raw source code to machine code, or raw source code to bytecode, or bytecode to machine code). In general, I have a very vague understanding of these concept.s I don't understand the basics of how compile time and run time works in D language, it wasn't really explained in the book so when I see terms like 'compile time' and 'run time' I only have a very vague idea of what these things mean and how the process works for D language when compared to other high level languages. Anything that happens at compile time means it happens while the compiler is translating the source. Anything that happens at run time happens while the compiled program is running. So take this example: ```d uint fourcc(char a, char b, char c, char d) { return (a << 0) | (b << 8) | (c << 16) | (d << 24); } // Here, fourcc is evaluated at compile time enum nv12 = fourcc('N', 'V', '1', '2'); void main() { writeln(nv12); // Here, fourcc is evaluated at runtime writeln(fourcc('Y', 'V', '1', '2')); } ``` When the compiler is processing this source code, it encounters the declaration of `nv12`. Since this is an `enum`, it's a compile-time constant that cannot be changed at run time. That means that any value used to initialize it must also be known at compile time. One way to do that would be to use a literal, but in this case it's initialized with a call to the `fourcc` function. So the compiler evaluates the fourcc function and uses the result as the initializer of `nv12`. In other words, the end result is just the same as if I had written `enum nv12 = 842094158`. The second call to `fourcc` in the main function is not in a compile-time context, so it does not happen at compile time. It happens at run time, i.e., when you double click the executable that the compiler and linker generated (or type its name on the command line). The general rule is: if a function call is in a context such that it *must* be evaluated at compile time, then the compiler will evaluate it. Otherwise, it's a normal run-time evaluation.
Re: Compile time vs run time -- what is the difference?
On 12/27/22 9:31 PM, thebluepandabear wrote: I am reading through the free book on learning D by Ali Çehreli and I am having difficulties understanding the difference between compile time execution and run time execution in D language. Compile time execution is running your code being compiled *while being compiled*. It allows you to generate compile-time data without having to write specialized "compile time only" constructs like templates or explicitly marked functions (as other languages typically do). Compile time data doesn't consume any runtime to execute, it's already done by the time your binary is running. It also is usable *at compile time*, for things like `static if`, or `mixin`. The intermediate language being executed is the parsed and semantically analyzed AST nodes. -Steve
Compile time vs run time -- what is the difference?
I am reading through the free book on learning D by Ali Çehreli and I am having difficulties understanding the difference between compile time execution and run time execution in D language. What I do understand is that compile time and run time are the two processes that your code goes through to be executed natively. Compile time is the first stage. During compile time, the compiler checks for basic syntax errors such as a missing semicolon, typos throughout the codebase. Then the run time stage begins. Other errors are only able to be spotted during run time such as exceptions, dividing by zero, assert blocks. In Java and some other languages, during compile time the code gets executed into Java bytecode. This also happens for C#. I don't know if there is an equivalent 'intermediate' language for D that your code gets translated to. In general, I have a very vague understanding of these concept.s I don't understand the basics of how compile time and run time works in D language, it wasn't really explained in the book so when I see terms like 'compile time' and 'run time' I only have a very vague idea of what these things mean and how the process works for D language when compared to other high level languages. Any help would be appreciated.
Re: Find out what type my class is being converted to for comparisons
On Tuesday, 18 October 2022 at 18:53:41 UTC, Matthew Rushworth wrote: I am in the process of building a matrix class (uni project, with my choice of programming language) and appear to have run into a problem that I'm not too sure how to fix. My class uses templates to define the shape of the matrix, although I'm not sure if that matters. As part of my class, I included a opEquals, but when I try to assert that a matrix created by multiplying with the identity matrix matches the output (I checked with liberal writeln()s to make sure they do) but my opEquals() function (I moved it out of the class as I kept getting errors saying it was supposed to be non-const, and couldn't figure out how to fix that either) just isn't called. --- Matrix code (the only bit of the class used by opEquals): ``` class Matrix(size_t X, size_t Y = X){ const size_t x_length = X; const size_t y_length = Y; double[X*Y] data; ... } ``` The entirety of opEquals: ``` /// both matrices have to have an identical shape to compare /// each element must be identical to match bool opEquals(size_t X, size_t Y)(const Matrix!(X,Y) m1, const Matrix!(X,Y) m2) { for (int i = 0; i < m1.data.length; ++i) if (m1.data[i] != m2.data[i]) return false; return true; } ``` and the code that excepts: ``` void main() { auto m = new Matrix!(2)(); m.data = [1.0,0.0,0.0,1.0].dup; auto n = new Matrix!(2)(); n.data = [2.0,3.0,4.0,5.0].dup; auto u = mult(m,n); writeln("u.data vs n.data:"); for (int i = 0; i < u.data.length; ++i) writeln(u.data[i], "\t", n.data[i]); // using opEquals() directly is working, but it doesn't seem to be being used //assert(opEquals(u,n),"\"opEquals(u, n)\" is failing."); // this works fine assert(u == n,"\"u == n\" is failing."); // this fails. Why? } ``` --- Any help would be very much appreciated. A way to figure out what the '==' is converting its arguments to would also be great, but I'm not sure it exists (beyond just sitting down and trying to work it out myself, of course) What's the reason for it being a class? struct makes more sense here, plus it'll be faster If it were a struct, you'd not need any of that, and you can also have operator overloading for your mult while also being able to check how many row/col at compile time, here an example: ```D import std; struct Matrix(size_t X, size_t Y = X) { enum x_length = X; // enum so it's available only at compile time enum y_length = Y; double[X * Y] data; // operator overloading Matrix opBinary(string op)(Matrix rhs) { static if (op == "*") { // // ** ADD YOUR MULT OPERATION HERE ** // static if (X == 2) { return Matrix(); } else static assert("not supported"); } else static assert(0, "Operator " ~ op ~ " not implemented"); } } void main() { // check equality by value: auto a = Matrix!(2)(); a.data = 0; auto b = Matrix!(2)(); b.data = 0; writeln("are they the same?: ", a == b); // it'll check for equality by value auto m = Matrix!(2)(); m.data = [1.0, 0.0, 0.0, 1.0]; auto n = Matrix!(2)(); n.data = [2.0, 3.0, 4.0, 5.0]; // here we can use the * operator! auto u = m * n; writeln("u.data vs n.data:"); for (int i = 0; i < u.data.length; ++i) writeln(u.data[i], "\t", n.data[i]); } ```
Re: Find out what type my class is being converted to for comparisons
On 10/19/22 00:43, Matthew Rushworth via Digitalmars-d-learn wrote: Thank you, that worked perfectly, not sure exactly what I did wrong, I'm assuming I forgot to make the parameter a const variable Object, the root of the class object hierarchy already defines an opEquals [1] and you need to overload/overwrite that for it to work properly. Only class methods are considered, hence ag0aep6g's suggestion. [1] https://dlang.org/library/object/object.op_equals.html
Re: Can someone tell me what the compiler thought I was trying to do?
On Wednesday, 19 October 2022 at 05:41:26 UTC, zjh wrote: Why always afraid to `add features`? C++ is `so complicated` ,but that people are not afraid to continue to `add features`. Look at the `emerging` languages, which are not crazy about `adding features`. Even `go` is adding generics.
Re: Can someone tell me what the compiler thought I was trying to do?
On Wednesday, 19 October 2022 at 05:50:18 UTC, zjh wrote: In my opinion, as long as `users` have reasonable needs, languages should added corresponding features, instead of becoming religions. `Some features` are very popular for users,I really don't know why they didn't add it. When you show `prejudice`, users are lost. Like `class`, when it can be used as the smallest `encapsulation unit`, it can provide `this feature` but intentionally does not. Just like when you ride a bicycle, but it has a `square` tire.
Re: Can someone tell me what the compiler thought I was trying to do?
On Wednesday, 19 October 2022 at 05:41:26 UTC, zjh wrote: Why can't do it `in one step`? Why always afraid to `add features`? C++ is `so complicated` ,but that people are not afraid to continue to `add features`. There is also `class level private`. I saw someone start it by himself, and he felt very happy. It completely conforms to the encapsulation, but it seems that the latest D has no switch about it. In my opinion, as long as `users` have reasonable needs, languages should added corresponding features, instead of becoming religions. `Some features` are very popular for users,I really don't know why they didn't add it.
Re: Can someone tell me what the compiler thought I was trying to do?
On Wednesday, 19 October 2022 at 04:59:40 UTC, mw wrote: ... Why can't do it `in one step`? Why always afraid to `add features`? C++ is `so complicated` ,but that people are not afraid to continue to `add features`.
Re: Can someone tell me what the compiler thought I was trying to do?
@mustuse as a function attribute was in the original version of the DIP. It was vetoed by Walter. Thus, only the type attribute remains in the accepted version. Let's continue the discussion here: https://forum.dlang.org/thread/nmornkxaxddfziqmq...@forum.dlang.org in general, it's about: command query separation principle
Re: Can someone tell me what the compiler thought I was trying to do?
On Wednesday, 19 October 2022 at 03:10:29 UTC, Mike Parker wrote: It's right there in the summary of the Final Review of the DIP that I linked above: https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1038.md#final-review I meant to say the summary of the formal assessment. One of the conditions of acceptance was this one: develop rules for handling covariance and contravariance when applied to functions. Paul opted instead to do just have it apply to types for now. A future enhancement can take on extending it to functions. As he noted above, that's the approach Rust took as well.
Re: Can someone tell me what the compiler thought I was trying to do?
On Wednesday, 19 October 2022 at 01:34:54 UTC, mw wrote: On Wednesday, 19 October 2022 at 01:30:23 UTC, H. S. Teoh wrote: On Wed, Oct 19, 2022 at 01:15:37AM +, Adam D Ruppe via it only applies to types, not to functions. Wat... so what's the use of it then? So it's not possible to mark the return value of an int function @mustUse without making, in theory, *all* ints @mustUse? I must confess I'm baffled as to the purpose of this strange design. Same, can't believe it. Is there any (design) doc about this? It's right there in the summary of the Final Review of the DIP that I linked above: https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1038.md#final-review
Re: Can someone tell me what the compiler thought I was trying to do?
On Wednesday, 19 October 2022 at 01:49:26 UTC, mw wrote: On Wednesday, 19 October 2022 at 01:38:27 UTC, Adam D Ruppe wrote: On Wednesday, 19 October 2022 at 01:34:54 UTC, mw wrote: Is there any (design) doc about this? scroll up, click the link from this very thread. https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1038.md#design-goals-and-possible-alternatives """ Rather than make either sacrifice, this DIP proposes a design that allows both rigor and simplicity to be maintained, and reserves the possibility for a future DIP to allow @mustUse as a function attribute. """ Another future DIP? I think this DIP is flawed for not using "@mustUse as a function attribute" @mustuse as a function attribute was in the original version of the DIP. It was vetoed by Walter. Thus, only the type attribute remains in the accepted version. FWIW, this is the same path that #[must_use] took in Rust. It was added originally as a type attribute only, and later had its usage extended to functions.
Re: Can someone tell me what the compiler thought I was trying to do?
On Wednesday, 19 October 2022 at 01:38:27 UTC, Adam D Ruppe wrote: On Wednesday, 19 October 2022 at 01:34:54 UTC, mw wrote: Is there any (design) doc about this? scroll up, click the link from this very thread. https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1038.md#design-goals-and-possible-alternatives """ Rather than make either sacrifice, this DIP proposes a design that allows both rigor and simplicity to be maintained, and reserves the possibility for a future DIP to allow @mustUse as a function attribute. """ Another future DIP? I think this DIP is flawed for not using "@mustUse as a function attribute"
Re: Can someone tell me what the compiler thought I was trying to do?
On Wednesday, 19 October 2022 at 01:34:54 UTC, mw wrote: Is there any (design) doc about this? scroll up, click the link from this very thread. https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1038.md#design-goals-and-possible-alternatives
Re: Can someone tell me what the compiler thought I was trying to do?
On 19/10/2022 2:30 PM, H. S. Teoh wrote: On Wed, Oct 19, 2022 at 01:15:37AM +, Adam D Ruppe via Digitalmars-d-learn wrote: On Wednesday, 19 October 2022 at 00:57:31 UTC, H. S. Teoh wrote: Has it really been implemented? I tested the latest git master, the following code doesn't compile: it only applies to types, not to functions. Wat... so what's the use of it then? So it's not possible to mark the return value of an int function @mustUse without making, in theory, *all* ints @mustUse? I must confess I'm baffled as to the purpose of this strange design. Oh but it gets better: From C23 draft: The nodiscard attribute shall be applied to the identifier in a function declaration or to the definition of a structure, union, or enumeration type. If an attribute argument clause is present, it shall have the form: ( string-literal )
Re: Can someone tell me what the compiler thought I was trying to do?
On Wednesday, 19 October 2022 at 01:30:23 UTC, H. S. Teoh wrote: On Wed, Oct 19, 2022 at 01:15:37AM +, Adam D Ruppe via it only applies to types, not to functions. Wat... so what's the use of it then? So it's not possible to mark the return value of an int function @mustUse without making, in theory, *all* ints @mustUse? I must confess I'm baffled as to the purpose of this strange design. Same, can't believe it. Is there any (design) doc about this?
Re: Can someone tell me what the compiler thought I was trying to do?
On Wed, Oct 19, 2022 at 01:15:37AM +, Adam D Ruppe via Digitalmars-d-learn wrote: > On Wednesday, 19 October 2022 at 00:57:31 UTC, H. S. Teoh wrote: > > Has it really been implemented? I tested the latest git master, the > > following code doesn't compile: > > it only applies to types, not to functions. Wat... so what's the use of it then? So it's not possible to mark the return value of an int function @mustUse without making, in theory, *all* ints @mustUse? I must confess I'm baffled as to the purpose of this strange design. T -- Doubt is a self-fulfilling prophecy.
Re: Can someone tell me what the compiler thought I was trying to do?
On Wednesday, 19 October 2022 at 00:57:31 UTC, H. S. Teoh wrote: Has it really been implemented? I tested the latest git master, the following code doesn't compile: it only applies to types, not to functions.