Re: Why is Phobos `Flag` so overthought ?
On Monday, 6 May 2024 at 17:55:49 UTC, user1234 wrote: I think this just works: ```d enum Flag : bool { no, yes } alias AllowVancancy = Flag; // example usage ``` ```d import std.stdio : writeln; enum Flag : bool { no, yes } alias Traditional = Flag; alias Color = Flag; void hello(Traditional traditional, Color color) { if (traditional && color) { writeln("\x1b[31;1mhello world\x1b[0m"); } else if (traditional && !color) { writeln("hello world"); } else if (!traditional && color) { writeln("\x1b[31;1mHello, world!\x1b[0m"); } else { writeln("Hello, world!"); } } void main() { hello(Color.yes, Traditional.yes); // this is wrong, but accepted } ```
Re: Challenge Tuples
On Friday, 26 April 2024 at 13:25:34 UTC, Salih Dincer wrote: You have a 5-item data tuples as Tuple(1, 2, 3, [1, 3], 5) and implement the sum (total = 15) with the least codes using the sum() function of the language you are coding... Nim: ```nim import std/[math, typetraits, macros] macro unrollRange(low, high: static int; name, body: untyped) = result = newStmtList() for i in low ..< high: result.add(newBlockStmt(newStmtList( newConstStmt(name, newLit i), copy body ))) let t = (1, 2, 3, @[1, 3], 5) var arr: seq[int] unrollRange(0, t.tupleLen, i): arr.add t[i] doAssert arr.sum == 15 ``` vs. D 1. there's no `each` on tuples 2. there's no static for loop, so a macro is needed for the tuple indices 3. `add` is making use of the same overload as D's `~=`
Re: macOS Sonoma Linker Issue
On Thursday, 21 December 2023 at 22:19:07 UTC, Renato wrote: LDC is slow and makes huge multi-MB binaries (is that normal?). DMD seemed much better to me. But at least LDC works :) so will use that for now. On my setup ldc generates small binaries and dmd generates huge ones. The difference is about dynamically linking Phobos or not. Try ldc with --link-defaultlib-shared
Re: Changing behavior of associative array
On Sunday, 17 December 2023 at 00:10:56 UTC, Kevin Bailey wrote: instead it seems like 'm' is a pointer to a std::map, that is initialized on use if null. (I think it's that latter part that gives the illusion of being already initialized.) Yes: https://dlang.org/spec/hash-map.html#construction_and_ref_semantic
Re: Changing behavior of associative array
On Saturday, 16 December 2023 at 22:44:16 UTC, Dennis wrote: That's because `m[f] = 1` initializes the associative array to something non-null. If you pass a `null` AA to a function which adds things, the caller will still have a null pointers. I've gotten this error in deployed Perl. Whenever the ceremony of creating a data structure is reduced, people can lose sight of when that happens. Here's a less common gotcha: ```d void main() { import std.stdio : writeln; int force_realloc(ref int[] seq) { foreach (int i; 1 .. 1_000_000) { seq ~= i; } return 1234; } int[] a = [4321]; writeln(a[0]); // 4321, of course a[0] = force_realloc(a); writeln(a[0]); // still 4321 } ``` The `a[0]` on the left of the assignment is decided early, and then force_realloc() changes what the location should be.
Re: surviving wasm
On Wednesday, 13 December 2023 at 20:40:20 UTC, monkyyy wrote: so long term planning on wasm raylib; I want compatibility with the good parts of the std, the std is causal about using libc while ldc-wasm half-baked implication is missing a bunch of basically worthless symbols but given the std is 1 million lines of code it will be a perennial problem that I make something work natively, I try it in wasm, it breaks citing a random core lib at a random line; the options I know about are: 1. use a "team betterc" personal std that doesn't have the apis I want, apis I know and probably limited 2. merge "use libc less" upstream to a std that has been slow to merge changes and probably doesnt care about wasm 3. fork the std 4. maintain patches to the std that go in and rewrite them live with root :D what could go wrong 5. make my own personal std that matches the std api of the parts I use I hate all these options 6. statically build against musl and include it in the wasm binary. Since phobos is slow to change, its libc dependencies will also be slow to change, and you can work on reducing how much musl goes into the binary. Musl's MIT-licensed and D has ImportC; maybe this can be upstreamed as a pseudo-libc-less build option. People who don't care about wasm may still care about dodging glibc due to binary portability hassles with deployment to older servers. ldc already uses musl on Alpine Linux, popular with containers.
Re: Advent of Code 2023
On Monday, 4 December 2023 at 03:50:47 UTC, Siarhei Siamashka wrote: On Monday, 4 December 2023 at 03:07:07 UTC, matheus wrote: import std.stdio; import std.algorithm; import std.array; import std.format; import std.conv; import std.string; ... Why do you do multiple imports instead of one import std;? I means is there any difference in CT? The code indeed compiles faster with fewer imports and this pays off in the long run for the actively developed large projects. Additionally, it's a good idea not to pollute the namespace with the functions that the developer has no intention to use. ``` dmd -betterC hellobc.d ran 6.18 ± 0.33 times faster than dmd hellosel.d 19.76 ± 1.06 times faster than dmd hellostd.d ``` 26ms, 136ms, 470ms. 16MB, 56MB, 154MB. -betterC with selected import of core.stdc.stdio selected import of std.stdio.writeln import std. D has the capability to compile extremely quickly. dmd compiles itself in a second or two. But it also gives you plenty of opportunities to trade that for convenience.
Re: Advent of Code 2023
On Sunday, 3 December 2023 at 23:44:43 UTC, Julian Fondren wrote: ```d if (str[i..$].startsWith(key)) return value; ``` Corrected. The other doesn't compile, unless you never run it with -version=Part2 ...
Re: Advent of Code 2023
On Saturday, 2 December 2023 at 13:33:33 UTC, Johannes Miesenhardt wrote: I am a bloody beginner so if there are any things that are very wrong with this please point them out. The fact that I need a template for accepting both a string and a char[] is very weird but I went with it. I am also curious if there is a better way for the reversible for-loop to happen. I saw foreach and foreach_reverse but I don't think that helps me here, since I swap them out based on a runtime argument. Rather than putting `version = Part2;` in the source, you can specify that on the commandline. This doesn't work with rdmd, but these work: ``` $ dmd -run day1.d $ dmd -version=Part2 day1.d $ ldc2 --d-version=Part2 --run day1.d $ gdc -fversion=Part2 day1.d && ./a.out ``` Rather than the template you could only accept `immutable(char)[]` and use `str.representation.assumeUTF` to get that from a string, without any extra allocation. There's a table at https://d.minimaltype.com/index.cgi/wiki?name=string+type+conversions that might be helpful (although I notice the unicode tests have some bitrot due to increased safety in the language.) You may still want a template though, to specialize on the `reverse` variable. That only changes these lines: ```d int findNum(bool reverse)(immutable(char)[] str) { ... auto firstNum = findNum!false(str.representation.assumeUTF); auto secNum = findNum!true(str.representation.assumeUTF); ``` Bonus from using a dynamic array: it would be much more annoying to have `reverse` as a template argument if you were still relying on an implicit `T` parameter at the callsite. And, `unittest {}` is a great feature of d. Instead of editing your code to run tests, changing things while working with the real input, not realizing that you broke your tests, then getting timed out when you submit your answer to AoC, you can doublecheck just before submission that `dmd -unittest -run day1.d` still passes. In your loop over numberMap, you could use ```d if (str[i..$].startsWith(key) == key) return value; ``` Otherwise, I think it's fine good. People might differ on style, but it doesn't look bad at all compared to some other implementations I've seen. The several ternary operators are the only awkward bit. Since you're a beginner you might find it interesting to implement a range that yields chars in reverse order, and have `findNum` take a range.
Re: D: Convert/parse uint integer to string. (@nogc)
On Tuesday, 28 November 2023 at 08:51:21 UTC, Mark Davies wrote: I did it this way ... You always print the full array of bytes this way. Output piped to `od -c` is ``` 000 1 2 3 4 5 377 377 377 377 377 \n - 1 2 3 4 020 5 377 377 377 377 \n ``` Those 377s are `char.init`, 0xFF. On Tuesday, 28 November 2023 at 09:43:47 UTC, Dom DiSc wrote: For a 'long' 10 characters is likely to be not enough (long max is 9223372036854775808 which has 19 chars, and you should reserve additional one for the sign and one for the terminating null), so I would at least recommend using char[21]. Signed max is all bits but the sign bit set, so 7FFF..., so signed max is always an odd number. d can confirm: ``` $ rdmd --eval 'writeln(long.max)' 9223372036854775807 $ rdmd --eval 'writeln(2+to!string(long.max).length)' 21 ``` There's no terminating NUL here, which might be an oversight. with char[10] your function becomes a big hole in your security, as it can easily be misused to write 10 bytes of freely selectable garbage behind your allocated memory. This is D though, so without separately disabling bounds checks, there's an error: ``` core.exception.ArrayIndexError@d1.d(22): index [18] is out of bounds for array of length 10 ``` or with -betterC: ``` d1: d1.d:21: Assertion `array index out of bounds' failed. Aborted ``` Here's a minimal edit to fix the `char.init` output: ```d char[] longToString(long n) @nogc { static char[21] x; size_t length; ulong power; x[0] = '-'*(n<0); long t = (n<0)*-n + (n>0)*n ; while (n != 0) { power++; n /= 10; } length = power; power -= (x[0] != '-'); while (t > 0) { x[power] = (t % 10) + '0'; power--; t /= 10; } return x[0 .. length]; } ``` As you can see, slices from this longToString are good until the next call to it. The other C-like way to manage memory is to pass in the buffer to use, which in D can be a slice of a static array on the caller's stack. You'll probably have a much better time with manual memory management if you use custom allocators.
Re: D: Declaring empty pointer variables that return address inside function calls?
On Thursday, 23 November 2023 at 20:13:59 UTC, BoQsc wrote: Nothing wrong. It would be just a more concise compact way to do the same. Also I mostly wanted to know if something like that is already possible in D language. It's not a huge loss if it is not possible. This is possible in Go: you dereference a literal constructor and it's either built on the stack or the heap depending on escape analysis. Example: ```go package main import "fmt" type T struct { data [5]byte } func usebuffer(a *T) *T { a.data[0] = 1 a.data[4] = 10 return a } func f() *T { return usebuffer({}) // <-- } func main() { fmt.Println(f()) } ``` which is very close to this D that is explicitly allocating on the heap: ```d class T { byte[5] data; } T usebuffer(T a) { a.data[0] = 1; a.data[4] = 10; return a; } T f() { return usebuffer(new T()); // <-- } void main() { import std.stdio : writeln; writeln(f().data); } ``` Which if you want stack allocation, is very similar to: ```d class T { byte[5] data; } T usebuffer(T a) { a.data[0] = 1; a.data[4] = 10; return a; } void main() { import std.stdio : writeln; import std.typecons : scoped; writeln(usebuffer(scoped!T).data); } ``` but, I don't actually know if this is safe.
Re: mixin under -betterC
On Thursday, 23 November 2023 at 17:46:55 UTC, DLearner wrote: I just find it surprising that your suggestion worked, but the (slightly simpler) earlier version did not. The `enum` answer? That also works, but you have to make a change at the callsite as well, to `mixin(mxnTest!("Var_A", "Var_B"));` - passing the strings as template rather than functional arguments.
Re: mixin under -betterC
On Thursday, 23 November 2023 at 16:33:52 UTC, DLearner wrote: Why is this so, bearing in mind the concatenations are executed at compile, not run, time? If you compile without -betterC, it'll work, but if you examine the result you'll find that the mxnTest function is still compiled into the result. D makes it so convenient to use functions at compile-time that there's no clear distinction for functions that should only exist at compile-time. Make mxnTest a template: ```d string mxnTest()(string strVar1, string strVar2) { ^^ ```
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 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: D: How to check if a function is chained? a().b().c();
On Saturday, 18 November 2023 at 07:47:19 UTC, BoQsc wrote: `program("someProgramName").pipe("someOtherProgramName");` Executes and pipes output to another program. `program();` - Only executes the program. Serious answer: have a function handle this, instead of the semicolon. `program("p1").pipe("p2").run;` - does that `program("p1").run;` - does the other Supposedly this is the "builder pattern" but the wikipedia entry seems to be deliberately bad. Unserious answer, especially unsuitable for your concrete example where you probably want subprocesses to run reliably and in order: do something with object lifetime functions. ```d import std.stdio : writeln; class Program { string program; bool used; this(string p) { program = p; } ~this() { if (!used) writeln("You forgot to chain program: ", program); } } Program a(string p) { return new Program(p); } void b(Program p) { p.used = true; writeln("using program: ", p.program); } void main() { a("2"); a("1").b(); } ```
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.
Re: Weird RDMD error when trying to import source file from subfolder.
On Wednesday, 1 November 2023 at 16:24:04 UTC, BoQsc wrote: **Error:** ``` rdmd testimport.d testimport.d(2): Error: module `next` from file waffle\next.d must be imported with 'import next;' ``` You import 'waffle.next', but the module is inferred to be 'next'. If put `module waffle.next;` at the top of next.d, this works.