Re: Address of a class object
On 1/4/23 13:43, H. S. Teoh wrote: > You do realize that the compiler is free to reorder local variables on > the stack, right? ;-) Of course. :) I was trying different strategies to catch the compiler (dmd here) in a single act of 8-byte object alignment as reported by .alignof. Another thing the compiler is free for class members is to reorder them. I also theorized perhaps the compiler was also considering the alignment of a member. But as expected, char[1] does have 1 alignment and it can't be the reason in this case. (Again, there is no problem here; we are just learning.) > implementation-specific details RazvanN or Dennis may chime in on that. Ali
Re: Address of a class object
On 1/4/23 12:02, Steven Schveighoffer wrote: > On 1/4/23 2:27 PM, Ali Çehreli wrote: >> I put the objects into a 2-length >> static array but the difference was still 0x20. (?) > > Are you putting the class *references* in a 2-length static array? I lied. As I could not put the objects in a static array, I put them on the stack with the 'scope' keyword and the difference was still 0x20. (Of course, I could emplace the objects myself in my static array but that wouldn't prove anything about why the current alignment appears to be 0x20.) > stop worrying about the addresses > given out by the GC No worries; just trying to explain... Ali
Re: Address of a class object
On 1/4/23 11:27, Ali Çehreli wrote: > writeln("hidden 0: ", hiddenValue(addr, 0)); > writeln("hidden 1: ", hiddenValue(addr, 1)); Silly me! :) Those members have names: writeln("__vptr : ", obj.__vptr); writeln("__monitor : ", obj.__monitor); https://dlang.org/spec/abi.html#classes Ali
Re: Address of a class object
On 1/4/23 10:48, H. S. Teoh wrote: > Allocations are not necessarily consecutive; the GC may have its own > strategy of allocation that doesn't follow a linear sequence. That was one of my guesses. So, I put the objects into a 2-length static array but the difference was still 0x20. (?) > Furthermore, GC-allocated blocks may be larger than the request size > because there may be some extra management information stored in the > block (but outside the pointer range returned). Good point. I think the minimum size of a dynamically allocated memory of the current GC implementation is 32 bytes. I've just realized that I was confusing myself by thinking the object pointer that cast(void*) produces was the first member's address. I was wrong: That is the address of the first of the two hidden members (the vtbl pointer and the monitor). My current guess is, although it could be a void*, the alignment of the first of those hidden members is 16. Now that I have a more correct understanding, the following program prints those hidden members. One of the examples shows the monitor of an object used with 'synchronized' is non-null. import std.stdio, std.traits; class MyClass { char[1] c; } void main() { writeln(" Size Alignment Type\n", "="); size_t size = __traits(classInstanceSize, MyClass); size_t alignment = classInstanceAlignment!MyClass; writefln("%4s%8s %s",size, alignment, MyClass.stringof); // Apologies for using lower-cased variable names. :) auto a = new MyClass(); auto b = new MyClass(); printObject!a; printObject!b; auto withMonitor = new MyClass(); synchronized (withMonitor) { // This object's "hidden 1" (the monitor) will not be 'null' printObject!withMonitor; } // This object's "hidden 0" (vtbl pointer) will be different: class SubClass : MyClass { } auto sub = new SubClass(); printObject!sub; } void printObject(alias obj)() { writeln("\n"); writeln("name: ", obj.stringof); const addr = cast(void*)obj; writeln("address : ", addr); writeln("hidden 0: ", hiddenValue(addr, 0)); writeln("hidden 1: ", hiddenValue(addr, 1)); } void* hiddenValue(const(void)* obj, size_t index) { alias HiddenType = void*; auto ptrToHiddens = cast(HiddenType[2]*)obj; return (*ptrToHiddens)[index]; } Here is the output: Size Alignment Type = 17 8 MyClass name: a address : 7F4009D48000 hidden 0: 558A1E172520 hidden 1: null name: b address : 7F4009D48020 hidden 0: 558A1E172520 hidden 1: null name: withMonitor address : 7F4009D48040 hidden 0: 558A1E172520 hidden 1: 558A20164B80 <-- non-null monitor name: sub address : 7F4009D48060 hidden 0: 558A1E172630 <-- Different vtbl for sub-class hidden 1: null Ali
Re: Address of a class object
On 1/3/23 20:01, Paul wrote: > Size Alignment Type > = >17 8 MyClass > > MyClassObj1 MyClassObj2 > 27727202000 27727202020 > ``` > If my size is 17 bytes and my alignment is 8 bytes, shouldn't my > MyClassObj2 in this example be @ 277272020**18** ? Good question. I made some guesses about object layouts, GC allocation schemes, etc. but did not like any of them. Ali
Re: Why does this code only work with `T` and not `typeof(T)`?
On 1/3/23 20:11, thebluepandabear wrote: > if I replace the `isDrawable` template with the > following (using `typeof`), the code does not compile: It must be because T is already a type. It's the same reason why the following code fails to compile: void main() { alias T = int; alias TT = typeof(T); } Error: type `int` is not an expression And the error message tells us typeof requires an expression. What you can do is to use T.init and the code should now work like the following does: alias TT = typeof(T.init); Ali
Re: Is there a way to enforce UFCS?
On 1/3/23 19:42, thebluepandabear wrote: > @property { As your post proves, that feature is at most half-baked and is discouraged. Today, there is just one known obscure effect of using it. > void name(string name) { > _name = name; > } > d.name = "Poodle"; > In the code we can see that we have utilized UFCS (universal function > call syntax) UFCS is for calling free-standing functions as if they are member functions. Since your example already uses member functions, this feature is not UFCS. And I don't think it has a name. It is always possible to pass a single-argument with the assignment syntax: void foo(int i) {} void main() { foo = 42; } Pretty wild! :) But that's what makes your assignment above work. (Not UFCS.) > not enforced [...] we can > do the following in our code: > d.name("poodle"); I don't see a problem with that. :) > I am disappointed that `@property` does not Many people are disappointed that @property is pretty much useless. > is there a way to enforce D gives us the tools to do that but it's not trivial. The function can return an object that represents a variable (member variable or not). And an assignment to that representative object can set the actual variable. However, I tried to achieve it with an intermediary object but failed because the same ="Poodle" syntax broke it and demanded that we type the empty parenthesis. So, I think what you want does not exist. // I have a feeling something similar exists in Phobos // but I could not find it. // // This is a reference to any variable. struct MyRef(T) { T * ptr; void opAssign(T value) { *ptr = value; } void toString(scope void delegate(in char[]) sink) const { sink(*ptr); } } // This is a convenience function template so that // the users don't have to say e.g. MyRef!string // themselves. (See name() below.) auto myRef(T)(ref T var) { return MyRef!T(); } class Dog { @property name() { return myRef(_name); } private { string _name; } } void main() { Dog d = new Dog(); // Great: The following won't work. // d.name("poodle"); // However, now there is the empty parenthesis. :( d.name() = "Poodle"; import std.stdio; writeln(d.name); } Ali
Re: Address of a class object
On 1/1/23 01:01, Paul wrote: > ...on my laptop it prints... > ``` > Size Alignment Type > = > 9 4 MyClass > > 4FFB20 4FFB24 > ``` > If the size of MyClass is 9 bytes why do MyClassO1 & O2 addresses only > differ by 4 bytes? As matheus said, classes are reference types, meaning, class variables are implemented as pointers. The values above are the addresses of those pointers. The fact that those values are different by 4 tells us that the code was compiled for 32 bits. On the other hand, matheus's values were 8 apart because that compilation was 64 bits. > So, I guess my question is actually how do I print out the addresses of > the MyClassO1 & O2 objects themselves? You must have missed my earlier answer: You need to cast the variable to 'void*'. That special operation will give you the address of the object. I am adding the following last line to matheus's example: // ... writeln("\n",&(MyClassO1.c),"\t",&(MyClassO2.c)); writeln("\n",cast(void*)MyClassO1,"\t",cast(void*)MyClassO2); The output: [...] 7F125FE770107F125FE77030 <-- The addresses of the 'c' members 7F125FE770007F125FE77020 <-- The addresses of the objects The reason why objects are 0x10 bytes before the 'c' members is because a class object has two hidden initial members: the vtbl pointer and the monitor, both of which are size of a pointer (4 on your system, and 8 on matheus's system and mine). Additionally, if you define the class as extern(C++), there will not be the monitor member. The reason for that is C++ does not have that concept and it would break interoperability. Ali
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: Address of a class object
On 12/31/22 16:35, Paul wrote: > Can I acquire the address of a class object, Answering that question literally, yes, you can by casting the class variable to void*. But note: 'class object' means the instance of class in D. > not a class variable (i.e. > the instantiations of the class) D terminology is different there: A class variable is a reference to the class object (that carries the member variables, etc. of a class instance.) auto c = new C(); 'c' is the *variable*, providing access to the *object* in dynamic memory. > but the object definition itself? As H. S. Teoh answered, Python etc. can do that but not D's compilation model. The following program tries to demonstrate that the members are offset two void* sizes further from the address of the object: class C { int i; } void main() { auto c = new C(); const likelyOffsetOfMembers = 2 * (void*).sizeof; // HERE: const objectAddrInDynamicMemory = cast(void*)c; assert(objectAddrInDynamicMemory + likelyOffsetOfMembers == ); } If the class is defined as extern(C++), then you must replace 2 above with 1: extern(C++) class C { int i; } Ali
Re: dChar Error
On 12/30/22 17:22, Salih Dincer wrote: > I guess there is no other way but to overload. Since the bodies of all three overloads are the same except some types, they can easily be templatized. > This is both the safest and the fastest. I didn't think Values is fast with string copies that it makes. ;) I think it was only for showing the byte values but you can do the same by casting to ubyte[] as well. Also, your Fun could work only with string literals; so I used function parameters. import std.traits : isSomeString; // isSomeString may or may not be useful below. (?) auto Fun(S)(S str) if (isSomeString!S) { import std.traits : Unqual; import std.conv : to; alias T = Unqual!S; // Note: The following may or may not copy the string // depending on whether S is the same as T. return str.to!T; } void printBytes(S)(S str) { import std.stdio : writefln; import std.conv : to; // The following cast does not copy anything. writefln!"%(%02X-%)"(cast(ubyte[])str); } void main() { printBytes(Fun("β€Ş")); // CE-B2-E2-82-AC-C5-9E printBytes(Fun("β€Ş"w)); // B2-03-AC-20-5E-01 printBytes(Fun("β€Ş"d)); // B2-03-00-00-AC-20-00-00-5E-01-00-00 } Ali
Re: dChar Error
On 12/30/22 13:54, matheus wrote: > But yes I think it will generate a copy (mutable) based on this test: In this case it does copy but in the case of dchar[] to dchar[], there will be no copy. Similarly, there is no copy from immutable to immutable. > the address is different Good test. :) > But I couldn't find if the target will be mutable, but I think it will > be, The target will always be the type the programmer specifies explicitly. (dchar[] in this case.) Ali
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: Can you simplify nested Indexed types?
On 12/27/22 07:09, Sergei Nosov wrote: > Basically, my idea is to apply `indexed` to an array several times and > have all the intermediaries saved in the same variable. There may be other ways of achieving the same goal without assigning to the same variable. > I wonder, if there's a way to "collapse" or "simplify" the > `Indexed!(Indexed!(int[], Result), Result)` type to just > `Indexed!(int[], Result)` ? If what you are looking for is a way of defining a variable for "any InputRange that produces a specific type (size_t in this case)", then there is inputRangeObject, which uses OOP: https://dlang.org/phobos/std_range_interfaces.html#InputRange I have an additional example here: http://ddili.org/ders/d.en/ranges_more.html#ix_ranges_more.inputRangeObject Ali
Re: Confusion about `Random`
On 12/24/22 09:58, jwatson-CO-edu wrote: >> ~static this() Should be 'static ~this()'. >> ~shared static this() Should be 'shared static ~this()'. > thank you all Happy to be helpful... Ali
Re: Confusion about `Random`
On 12/24/22 08:18, jwatson-CO-edu wrote: > On Friday, 23 December 2022 at 07:25:23 UTC, Salih Dincer wrote: >> You can try using static this. >> >> ```d >> import std.random; >> >> static this() { } // can try using static this() blocks: executed when a thread a starts (the program has at least one thread: the main thread); so you can put initializations here ~static this() blocks: counterparts of 'static this', executed once for each thread that is terminating shared static this() blocks: executed once per program (executed by the main thread) ~shared static this() blocks executed once per program when the program is terminating >> "rand" : () => new Atom(rand01) That's the lambda (ananymous function) syntax. The "rand" key of an associative array is being associated with the function after the ':' character. In the code above, the function creates a new Atom object. So, when the following code is executed: primitiveSymbols["rand"] the same lambda would be returned but the execution of that lambda as the following primitiveSymbols["rand"]() would return a new Atom which would make a call to the rand01() function and get a new random number from the same 'rnd' object. Ali
Re: Does 'ref' turn into a pointer during compile time?
On 12/21/22 16:43, thebluepandabear wrote: > Say you have the following function that takes in a `ref` parameter: > > ```D > void modify(ref int num) { > num += 5; > } > ``` > > Does the compiler turn that into the code below? > > ```D > void modify(int* num) { > num += 5; Rather: *num += 5; > } > ``` > > I was just wondering whether or not this is the case because I don't > think this was touched in the book about D I am reading. Yes, references are realized by pointers by CPUs; so that's how the code is compiled as well. Pointers are considered to be one of the most difficult concepts for beginners (who the book was supposed to target). That's why I tried to hold it off as much as possible. I think once the concept of a reference is understood, pointers should be easy to understand. That's why I say "Behind the scenes, D's higher-level concepts (class variables, slices, associative arrays, etc.) are all implemented by pointers." only later in the book on the pointers page: http://ddili.org/ders/d.en/pointers.html Ali
Re: Is there such concept of a list in D?
On 12/19/22 14:14, thebluepandabear wrote: > Yeah I am sure it was on this thread. One of the posts was at > https://forum.dlang.org/post/kzvnajixjdnlcupsl...@forum.dlang.org, it > now shows 'Not Found'. Then I don't know. (?) However, I realize my ThunderBird "evidence" is useless because if the disapparance happened before my ThunderBird connected since its last time, it wouldn't have a copy of the posts. (My ThunderBird does not connect automatically especially when the laptop lid is closed. :) ) Ali
Re: Is there such concept of a list in D?
On 12/19/22 13:45, thebluepandabear wrote: > On Monday, 19 December 2022 at 21:41:45 UTC, thebluepandabear wrote: >> Why did my replies here to someone else get deleted? > > Myself and this other person's reply to this thread randomly got removed > for no reason, I would appreciate an explanation Are you sure it was this thread? What were in those posts? Perhaps they were posted on another thread? I follow these newsgroups with ThunderBird, which naturally keeps local copies of the posts. I've just gone through all posts in this thread and I see no difference between ThunderBird's cache and the forum interface's cache. Note that ThunderBird does not delete any post even if a moderator removes a posting from the newsgroup. For example, when a spam gets posted, my ThunderBird will show the post even after it's been deleted from the newsgroup server. Ali
Re: No need opUnary
On 12/18/22 08:21, Salih Dincer wrote: > Don't you think it's interesting that it doesn't need unary operator > overloading? Yes, it is interesting. I put comments to explain it to myself: import std.stdio; struct S { int value; /* The folowing declaration allows objects of this type to be implicitly convertible to 'int' (the return type of 'opCall'). In other words, since opCall returns 'int', now we know S objects can implicitly be used in place of an int. The value will be determined by calling opCall. For those of us who may not know opCall, it allows an object to be used as a function. For example, when you have an 'obj', you can do 'obj()'. (And as seen below, it returns 'int' for this struct.) (Note: It confused me for a bit because there are two opCall definitions below and they both return 'int'. However, there is no ambiguity because the compiler picks the one that takes no parameter for the following alias this.) */ alias opCall this; this(int i) { value = i; } /* I didn't know one could do the following. You are giving a new name (opAssign) to opCall. I wonder whether the compiler considers opCall for the assignment operation or whether it looks for a proper opAssign definition. (Too lazy to check...) */ alias opAssign = opCall; /* This is the function call operator that takes an 'int', supporting usages like obj(42). */ @property opCall(int x) { return value = x; } /* This is the function call opCall that takes nothing, supporting usages like obj(). */ @property opCall() inout { return value; } /* This is the operator overload for usages like 'obj += 42'. */ @property opOpAssign(string op)(int x) { write(":"); // came here before mixin("return value"~op~"=x;"); } // no need: opUnary(string op)(); } void main() { /* Ok, this is regular object construction. */ S a = S(10), /* Using a comma above is something I would never do but 'b' is another object being constructed regularly. */ b = S(-1); /* Since S does not define the '+' operation, I think the compiler looks and finds an implicit conversion, which happens to be to 'int'. I think the following expression is addition of two ints: 10 + (-1)' */ writeln(a + b); // 9 /* Although S does not support the ++ operator, the D compiler finds the += operation and replaces ++ with a+=1. And then a is implicitly converted to 'int', gets the value 11. Again, the expression is an int addition of 11 + (-1). */ writeln(++a + b); // :10 /* This uses opOpAssign. */ a += 10; // : /* This result makes sense. */ assert(a == 21); writeln("\n--"); writeln(-b); // 1 } Ali
Re: How is this code invalid?
On 12/16/22 18:20, H. S. Teoh wrote: > scratch space for computations, called the runtime > stack. I called it "function call stack" where I gave a very simplistic view of it here: https://www.youtube.com/watch?v=NWIU5wn1F1I=236s > (2) Use @safe when possible so that the compiler will tell you when > you're doing something wrong and potentially dangerous. Unfortunately, @safe is not as prominent in the book as it should be. Part of the reason is I think its implementation is not complete especially how it changes with -dip1000. Ali
Re: Unique!struct bug - Re: unique_ptr | Unique for autoclose handle
On 12/15/22 11:31, Nick Treleaven wrote: > On Wednesday, 14 December 2022 at 17:41:07 UTC, Ali Çehreli wrote: >> I've never used Unique but I think it has a bug (or a design issue?): >> Its destructor is the following: >> >> ~this() >> { >> if (_p !is null) >> { >> destroy(_p); >> _p = null; >> } >> } >> >> Because _p is a pointer, destroy(_p) will not dereference and destroy >> what it points to. I think this is a bug with Unique. I think it >> should do >> >> destroy(*_p); > > Now filed: > https://issues.dlang.org/show_bug.cgi?id=23561 Thanks. I was hoping others more experienced with Phobos implementation chime in. But to me, the intention is to destroy the object. One never wants to destroy a pointer as there is no operation there. As a minor proud moment, I do cover this issue: http://ddili.org/ders/d.en/memory.html#ix_memory.destroy > Do you think it's OK to just fix this or I think this is a bug because the documentation clearly talks about destroying the object: https://dlang.org/library/std/typecons/unique.html "When a Unique!T goes out of scope it will call destroy on the resource T that it manages, unless it is transferred. One important consequence of destroy is that it will call the destructor of the resource T." > do we need to do some kind of deprecation? The behavior is so different from the intention that I don't think anybody is using Unique anyway. :o) Ali
Re: unique_ptr | Unique for autoclose handle
On 12/14/22 09:41, Ali Çehreli wrote: > // According to documentation, the handler must be created dynamically: > // We make a unique owner for it: Ignore that part. It's a leftover from my experiments with Unique!Handle. Ali
Re: unique_ptr | Unique for autoclose handle
On 12/14/22 05:58, Vitaliy Fadeev wrote: > On Wednesday, 14 December 2022 at 11:30:07 UTC, Vitaliy Fadeev wrote: >> How to define HANDLE var ? What to return from procedure? How to call >> CloseHandle( h ) when variable destroyed? An obvious way is an RAII type where the destructor calls CloseHandle. > struct SafeHandle > { > Unique!void _safe; So you made Unique a member of SafeHandle. I've never used Unique but I think it has a bug (or a design issue?): Its destructor is the following: ~this() { if (_p !is null) { destroy(_p); _p = null; } } Because _p is a pointer, destroy(_p) will not dereference and destroy what it points to. I think this is a bug with Unique. I think it should do destroy(*_p); In any case, I would use a Handle RAII type that calls CloseHandle in its destructor. Here is the code that made sense to me: import std; // Some values and types to make the code compile: alias HANDLE = void*; alias LPCWSTR = string; enum INVALID_HANDLE_VALUE = null; enum FILE_SHARE_READ = 1; enum FILE_SHARE_WRITE = 2; enum NULL = null; enum OPEN_EXISTING = 1000; // Some mocks of system functions HANDLE CreateFileW(LPCWSTR path, int, int, void*, int, int, void*) { auto handle = cast(HANDLE)(new int(42)); writeln("Created ", handle); return handle; } int CloseHandle(HANDLE handle) { writeln("Closing ", handle); return 0; } // This is the RAII type for closing system handles struct Handle { HANDLE value; // Disabling copying and assignment @disable this(this); @disable typeof(this) opAssign(const(typeof(this))); this(HANDLE value) { this.value = value; writeln("Constructed Handle with ", value); } ~this() { const ret = CloseHandle(value); if (ret) { stderr.writefln!"Failed to close handle %s"(value); } } } Handle open_keyboard_device2( LPCWSTR path, int* error_number ) { // ... HANDLE dev_handle = CreateFileW( path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); // According to documentation, the handler must be created dynamically: // We make a unique owner for it: auto result = Handle(dev_handle); writeln("Exiting open_keyboard_device2"); return result; // if ( dev_handle.get() != INVALID_HANDLE_VALUE ) { // // ... // } // ... } void processDevice( ... ) { int err; auto dev_handle = open_keyboard_device2("foo", ); // set_keyboard_indicator2( dev_handle, KEYBOARD_CAPS_LOCK_ON ); // ... writeln("Exiting processDevice"); } void main() { processDevice(); writeln("Exiting main"); } The output of the program looks acceptable to me: Created 7F1BD5A7D000 Constructed Handle with 7F1BD5A7D000 Exiting open_keyboard_device2 Exiting processDevice Closing 7F1BD5A7D000 Exiting main Ali
Re: Is there such concept of a list in D?
On 12/13/22 14:21, areYouSureAboutThat wrote: > On Saturday, 10 December 2022 at 15:59:07 UTC, Ali Çehreli wrote: >> >> ... Object orientation don't go well with collections > > On what basis do you make that assertion? You stripped my answer. > i.e. Which aspect of OOP programming 'don't go well with collections'? > > Is it encapsulation? > > Is it inheritance? > > Is it polymorphism? > > Is it generics? (which is an integral part of OOP these days) I am impressed with the questions. Waiting for your answers... > As evidence against your assertion (just to start with): > C# -> System.Collections > C# -> System.Collections.Generic > C# -> System.Collections.Concurrent > > Only when you provide related proofs, can you come up with such an axiom. Or I can tell what I think, you counter, and we all learn. Proofs... Axioms... Pfft... Ali P.S. I apologize for everything I've done to you in the past. Don't forget: You can always forkit!
Re: Why can't rvalues be passed to a 'ref' parameter?
On 12/11/22 01:25, zjh wrote: > On Sunday, 11 December 2022 at 04:36:45 UTC, thebluepandabear wrote: > >> "The main reason for this limitation is the fact that a function >> taking a ref >> parameter can hold on to that reference for later use, at a time when >> the rvalue >> would not be available." >> > > > I only know that `rvalue` is a temporary value that will not be used, Temporary values can be used but they should not be stored for later. In this context, if the ref parameter were also 'scope', we should be able to pass rvalues. (See below.) > while `ref` is omitting a pointer. Yes, although it is still a pointer behind the scenes, 'ref' is syntax that avoids pointers. However, the situation has changed in D: It has been possible to pass rvalues by reference through the magic of 'in' parameters. This currently requires the -preview=in compiler switch, which makes 'in' parameters imply 'const scope': https://dlang.org/spec/function.html#in-params import std.stdio; struct S { string id; } void foo(in S s) { writeln("foo received ", s.id); } void main() { auto s = S("lvalue"); foo(s); foo(S("rvalue")); } Prints foo received lvalue foo received rvalue On can add a copy constructor to S to see whether 'in' is by-copy or by-value. Ali
Re: Function template as template parameter
On 12/11/22 05:54, Salih Dincer wrote: > On Sunday, 11 December 2022 at 09:43:34 UTC, Andrey Zherikov wrote: >> Note that callback parameter must be compile-time parameter as it >> represents a member of a type during introspection done by `foo`. > > I can't quite understand the question, this already works: I think the OP is trying to create an anonymous template. I don't think it's possible. The following works because the template has the name 'print': // Named template: static void print(int i)() { import std; writeln(i); } void main() { foo!print; } The following does not work when one attempts to use the template anonymously. Just trying to pass a template just like a lambda: foo!((int i)() { import std; writeln(i); }); Note how '(int i)()' is hoping to define a template. Ali
Re: Is there such concept of a list in D?
On 12/9/22 22:11, thebluepandabear wrote: > I was wondering more if there is an object oriented way of creating > arrays, Every collection has its own special interface. Object orientation don't go well with collections. For example, you wouldn't want indexing operator for a linked list. > like in Java there is an `ArrayList`, in C++ there is > `std::vector`, etc. They are all dynamic arrays behind the scenes. Arrays are so much better than linked lists that linked lists don't have much use outside of interviews. - Arrays use less memory - Provide constant time element access - Amortized constant time element addition - Constant time element removal in some cases (move the last element in place of the removed one) - Ability to sort to find elements in logN time later on - Arrays get special help from the CPU (e.g. cache prefetches) There isn't a single point in favor of linked lists. Ali
Re: printf, writeln, writefln
On 12/8/22 08:21, Salih Dincer wrote: > void stringCopy(Chars)(string source, > ref Chars target) >sample.stringCopy = cTxt; // disappeared ? char Nothing disappeared on my system. (?) Going off-topic, I find the expression above extremely confusing. I am used to assignment expression changing the value of the left hand side, but that expression changes cTxt. Very confusing... Such obfuscations make it very hard for me to understand what the code is trying to demonstrate. Ali
Re: gcc -E -dD; dstep; sqlite3
On 12/8/22 06:28, johannes wrote: > enum __FLT128_MAX__ = 1.18973149535723176508575932662800702e+4932F128; That literal is not legal D. The "F128" characters at the end are extra. Besides, D does not have a 128-bit floating point type. Ali (Sorry for double e-mail.)
Re: printf, writeln, writefln
On 12/6/22 15:07, johannes wrote: > 'write' prints out the address > of the first byte. This is odd to me because printf does the job > correctly. printf behaves as what you expect because %s means dereferencing the pointer values and printing the char contents until printf sees '\0'. > But I think to understand that write in D interpretes char* > as a pointer to a byte. Because it is. :) char* is nothing but a pointer to char. ('byte' exists as well, so I user 'char'.) > it seems the > formatting "%s" has another meaning in D ? Yes. %s means the string representation of the variable. Sring representation of a pointer happens to be the hexadecimal representation of its value. User-defined types can define a toSring() member function to decide how their string representation should be. %s is the default: write(x) or writeln(x) would print like %s would. This all works because these functions are templates, taking advantage of type deduction: They know the exact type of what they are printing. So, %s is known for that type. printf that came from C is not templatized, so the programmer has to tell it what to do like with %s. Ali
Re: Confused about something in the D book relating to precision
On 12/4/22 18:57, thebluepandabear wrote: > I am not understanding why Ali said there is a decimal mark if precision > is nonzero? > > How can a number have zero precision? That "precision" is referring to how many digits are printed after the decimal mark in the formatted output. > "the required digits after the decimal mark, the number of which is > determined > by precision (default precision is 6)" So, if we print with %e, we get 6 digits: enum f = 1.23456789; writefln!"%e"(f); Prints 1.234568e+00 There are 6 digits after the decimal point. Now 3 digits of precision: writefln!"%.3e"(f); Prints 1.235e+00 Now 0 precision, where the decimal point will disappear: writefln!"%.0e"(f); Prints 1e+00 > Well double has a precision of 15 Different meanings for the same word... > I feel like this section was explained poorly and it's confusing. I have to agree. Nobody really knows these by heart. Once you know what's available, you just come back and pick what you need for that occasion. Ali
Re: Idiomatic D using GC as a library writer
On 12/4/22 15:25, Adam D Ruppe wrote: > which would trigger the write barrier. The thread isn't > allowed to complete this operation until the GC is done. According to my limited understanding of write barriers, the thread moving to 800 could continue because order of memory operations may have been satisfied. What I don't see is, what would the GC thread be waiting for about the write to 800? Would the GC be leaving behind writes to every page it scans, which have barriers around so that the other thread can't continue? But then the GC's write would finish and the other thread's write would finish. Ok, here is the question: Is there a very long standing partial write that the GC can perform like: "I write to 0x42, but I will finish it 2 seconds later. So, all other writes should wait?" > The GC finishes its work and releases the barriers. So, it really is explicit acquisition and releasing of these barriers... I think this is provided by the CPU, not the OS. How many explicit write barriers are there? Ali
Re: Idiomatic D using GC as a library writer
On 12/4/22 12:17, Adam D Ruppe wrote: On Sunday, 4 December 2022 at 17:53:00 UTC, Adam D Ruppe wrote: Interesting... you know, maybe D's GC should formally expose a mutex that you can synchronize on for when it is running. .. or compile in write barriers. then it doesn't matter if the thread is unregistered, the write barrier will protect it as-needed! That's way beyond my pay grade. Explain please. :) Ali
Re: Idiomatic D using GC as a library writer
On 12/4/22 06:27, Sergey wrote: > if it will be possible to write > library in D and use it from > C/++/Python/R/JVM(JNI)/Erlang(NIF)/nameYourChoice smoothly it will be a > win. Years ago we tried to call D from Java. I realized that it was very tricky to introduce the calling thread to D's GC. D's GC needed to stop the world, which meant it would have to know what threads were running. You can never be sure whether your D library function is being called from a thread you've known or whether the Java runtime (or other user code) just decided to start another thread. We failed and D was replaced with C++. Ali
Re: Idiomatic D using GC as a library writer
On 12/4/22 05:58, vushu wrote: > I was worried if my library should be GC free May I humbly recommend you question where that thinking comes from? Ali P.S. I used to be certain that the idea of GC was wrong and the creators of runtimes with GC were simpletons. In contrast, people like me, people who could understand C++, were enlightened. Then I learned.
Re: Why can't D store all UTF-8 code units in char type? (not really understanding explanation)
On 12/2/22 13:18, thebluepandabear wrote: > But I don't really understand this? What does it mean that it 'must be > represented by at least 2 bytes'? The integral value of Ğ in unicode is 286. https://unicodeplus.com/U+011E Since 'char' is 8 bits, it cannot store 286. At first, that sounds like a hopeless situation, making one think that Ğ cannot be represented in a string. The concept of encoding to the rescue: Ğ can be encoded by 2 chars: import std.stdio; void main() { foreach (c; "Ğ") { writefln!"%b"(c); } } That program prints 11000100 1000 Articles like the following explain well how that second byte is a continuation byte: https://en.wikipedia.org/wiki/UTF-8#Encoding (It's a continuation byte because it starts with the bits 10). > I don't think it was explained well in > the book. Coincidentally, according to another recent feedback I received, unicode and UTF are introduced way too early for such a book. I agree. I hadn't understood a single thing when the first time smart people were trying to explain unicode and UTF encodings to the company where I worked at. I had years of programming experience back then. (Although, I now think the instructors were not really good; and the company was pretty bad as well. :) ) > Any help would be appreciated. I recommend the Wikipedia page I linked above. It is enlightening to understand how about 150K unicode characters can be encoded with units of 8 bits. You can safely ignore wchar, dchar, wstring, and dstring for daily coding. Only special programs may need to deal with those types. 'char' and string are what we need and do use predominantly in D. Ali
Re: Why can't D store all UTF-8 code units in char type? (not really understanding explanation)
On 12/2/22 13:44, rikki cattermole wrote: > Yeah you're right, its code unit not code point. This proves yet again how badly chosen those names are. I must look it up every time before using one or the other. So they are both "code"? One is a "unit" and the other is a "point"? Sheesh! Ali
Re: Syntax Sugar for Initializing a Fixed float Array as void*?
On 11/30/22 16:48, Ali Çehreli wrote: Functions are syntax sugar. :) And I remembered std.array.staticArray. One its overloads should be useful: import std; void main() { auto v3 = staticArray!(0.1f.repeat(5)); auto v4 = staticArray!5(0.1f.repeat); writeln(v3); writeln(v4); } Ali
Re: Syntax Sugar for Initializing a Fixed float Array as void*?
On 11/30/22 16:39, jwatson-CO-edu wrote: Is there a way to write a single statement that creates a void pointer that points to an initialized float array? See below: ```d float* arr = cast(float*) new float[4]; arr[0] = 0.1; arr[1] = 0.1; arr[2] = 0.1; arr[3] = 0.1; void* value = cast(void*) arr; ``` Functions are syntax sugar. :) import std; void* inittedArray(T)(T value, size_t count) { auto arr = new T[count]; arr[] = value; return arr.ptr; } void main() { auto v = inittedArray(0.1f, 5); // or something a little crazy: auto v2 = 0.1f.repeat(5).array.ptr.to!(void*); } Ali
Re: Thinking about the difference between fixed and 'dynamic' arrays.
On 11/29/22 15:25, DLearner wrote: > 'dynamic array' is > not a reasonable description for a construct that behaves like > VarArr2[3] becoming 40. I agree with you: It has always bothered me to call the following a dynamic array: int[] arr; 'arr' is not a dynamic array but the slice interface. Dynamic arrays are owned by the D runtime and are always nameless. Ali
Re: Is there a formula for overflow?
On 11/29/22 19:07, thebluepandabear wrote: > But the book doesn't talk about why the D compiler came up with these > results The compiler doesn't do anything special. It's all about the lack of bits to store the value. If the result needs 33 bits but the type has only 32 bits, the contribution of the highest bit is simply lost. Ali
Re: dirEntries removes entire branches of empty directories
On 11/14/22 14:41, kdevel wrote: > the ftw version gets the whole information from readdir alone. Created an enhancement request: https://issues.dlang.org/show_bug.cgi?id=23512 Ali
Re: Assigning parameter on entry to a function and assigning back on exit
On 11/25/22 05:06, Victor Porton wrote: >> A function argument that is both input and output, may be passed to >> the function either as reference or do two assignments: on entry of >> the function it is assigned to the parameter, on exit it is assigned >> back. The way I understand it with C, C++, and D, if there were such an assignment back, that could only be performed by the caller. I don't think the ABIs of those languages support that behavior. I think there is only pass by reference for out parameters. Ali
Re: Is defining get/set methods for every field overkill?
On 11/20/22 14:37, [] () {} () wrote: > so, as I understand it, your're against the use of private, against the > use of class, and against the use of encapsulation. I never implied any of that. > .. good luck with your career as a software engineer (but please, for > all our sakes, don't work on any safety-related systems, and especially > not the ones running in my car). I haven't written any code that runs on the car yet but I did and still do work in autonomous vehicle projects: https://techcrunch.com/2017/04/04/daimler-and-bosch-fully-autonomous-cars-within-5-years/ (That partnership is no more at this time.) And coincidentally, to reply to your post that included Autosar, MISRA, etc. I am very well aware of those standards because I did contribute to the team that wrote our coding standards by going through every single one of their rules. As one would expect, there was no argument on whether to use getters and setters or direct public access for that project: We decided no public access to members. This discussion came to this point because you and I understood the question differently: I took the OP's question literally: "Is defining get/set methods for every field overkill?" You took the question as whether to define them for class hierarchies, safety-critical systems, etc. Ali
Re: Is defining get/set methods for every field overkill?
On 11/20/22 23:01, [] () {} () wrote: > On that basis, I might be tempted to agree with you're point of view -> > never, ever, ever, ever, use classes in D. That's not my point of view. Ali
Re: Is defining get/set methods for every field overkill?
On 11/20/22 00:31, [] () {} () wrote: > Quoted from that video (the one that you agree with): > > "I don't ever think that private .. private is like just .. shouldn't > even be used." > > "so I don't even use classes I just use struct so that everything is > always public .. and that in my opinion is the correct method." Yes, still agreeing with it. > If anyone wants to learn more about why encapsulated types > (classes) have shown to be so useful in my many years of programming, Hm. 'private' is about access control. Encapsulation is something else. > they can first pay me my fee. If I could, I would like to pay to have less of that please. :) Ali
Re: Is defining get/set methods for every field overkill?
On 11/19/22 01:43, [] () {} () wrote: > do it your way for the next 10 years, and > I bet you will eventually come to a different point of view ;-) Hm... I am responding without reading the rest of the thread so I don't know whether you've mentioned the 10 years more but here it goes: I hope 11 years will be sufficient to stop following guidelines blindly. Especially this specific one where a posted video has shown how wasteful it can be. > if you're just a hobyist programmer, then you're really free to do as > you please. I am a professional programmer and I do not write public accessors blindly. As stated before, they are written only when there is an invariant to protect. > but if you are a software engineer employed by a company, within a team > of other software engineers, then you have to a have framework that you > *all* work against. Agreed. > anyone who says otherwise, doesn't know what they're talking about. Agreed. > In my team, 'classes' do not have public member variables. not ever. I am not working there! :) And what about structs? ;) > another team is free to do as it pleases of course ;-) Thanks. :) > but members of that team will have a hard time getting into my team. Mutual feelings there... Ali
Re: Is defining get/set methods for every field overkill?
On 11/19/22 01:05, [] () {} () wrote: > All this because some programmer wanted to save a few key strokes, or > did not anticipate change, or did not anticipate the need to ensure data > is valid before assigning it, or returning it. > > So no. It's not overkill. It's called software engineering. I disagree. Engineering is about applying different solutions to different problems. Blindly following guidelines whether it is fit for purpose would be dogmatic, not pragmatic. Ali
Re: Is defining get/set methods for every field overkill?
On 11/18/22 20:13, [] () {} () wrote: > after 10 years of doing all that, you may well come to the conclusion > that public member variables are not such a great idea afterall ;-) It depends. Majority of my structs are pure data. When there is no invariant to protect, then there is no reason to write any accessor. If 10 years is mentioned to prove a point, I currently have 33 years of professional programming experience (37 including pure hobby years), so I must be right. ;) Ali
Re: Is defining get/set methods for every field overkill?
On 11/18/22 19:35, [] () {} () wrote: > I like to see an example, of a 'class type' with 'public' member > variables, somehow magically converted into both getter and setter using > UFCS, without breaking client code. UFCS was mentioned before in the same context but I think what is meant was the D feature where functions can be called without parenthesis. Let's say, we have a pure data type: struct Point { int x; int y; } void clientCode() { auto p = Point(); p.y = p.x + 42; } void main() { clientCode(); } It took me 20 years to first think that public access to members was extremely wrong to then realize that there may not be any problem with it at all. As you said, "business logic" (I prefer "invariants") warrants limiting access to members. Without anything to protect, it is just extra work for no reason at all. (I fully agree with the posted video.) Ok, let's say that the business requirements changed and we wanted to perform some business logic. Thanks to D's pragmatism, clientCode() does not change at all: struct Point { int x_;// Rename int y_;// Rename auto x() {// Getter return x_ + y_; } auto y(int value) { // Setter x_ = value * 2; y_ = value / 2; } } void clientCode() { auto p = Point(); p.y = p.x + 42; } void main() { clientCode(); } There: clientCode() is not broken. Ali
Re: Is defining get/set methods for every field overkill?
On 11/16/22 20:39, thebluepandabear wrote: > I am debating whether or not I should add getter methods to these > properties. If you are debating, then the answer is easy: you should not. :) Less code written means less bugs, more cohesion, easier refactoring, cleaner code, all good stuff... Even if a design requires e.g. a 'length' method, the default one should be a getter. A setter will come in the future only if 'length = 42' is clearly better than e.g. 'expandTo(42)'. > in other languages like Java it is a good practice: I've seen so many tutorials where any user-defined type immediately defines getters and setters. It is never good style to do that. There are good examples of where doing that is clearly wrong. For example, can a Date class really provide a setMonth() setter? It would be so wrong, I don't even know where to begin. (I remember talks by Kevlin Henney where he would use that example.) The guidelines I follow are simple in the following order: - Don't write any code until it makes sense :) - Don't write a getter until it makes sense - Don't write a setter until it makes sense Ali
Re: Actual lifetime of static array slices?
On 11/15/22 06:05, Siarhei Siamashka wrote: > Ali commented that "the > compiler cannot do anything about it in all cases and we wouldn't want > it to spend infinite amount of time to try to determine everything". Yes, that's my understanding. > This sounds like he justifies the compiler's failure and accepts this as > something normal. Despite my lack of computer science education, I think the compiler's failure in analyzing source code to determine all bugs is "normal". I base my understanding on the "halting problem" and the "separate compilation" feature that D supports. > The https://dlang.org/spec/memory-safe-d.html page also provides a > rather vague statement: "@safe functions have a number of restrictions > on what they may do and are intended to disallow operations that may > cause memory corruption". Which kinda means that it makes some effort to > catch some memory safety bugs. Exactly. My understanding is that @safe attempts to remove memory corruptions. @live is being worked on to improve the situation by tracking liveness of data. > This weasel language isn't very > reassuring, compared to a very clear Rust documentation. That's spot on. Ali
Re: Actual lifetime of static array slices?
On 11/14/22 19:05, Elfstone wrote: > @safe > int[] foo() > { > int[1024] static_array; > // return static_array[]; // Error: returning `static_array[]` > escapes a reference to local variable `static_array` That is trivial for the compiler to catch. > return null; > } > > @safe > A bar() > { > int[1024] static_array; > return new A(static_array[]); That one requires the computer to analyze the code to a deeper level. Yes, we are passing a slice to the A constructor but we don't know whether the constructor will store the slice or simply use it. Even the following can be safe but impossible to detect by the compiler: class A { @safe this(int[] inData) { data = someCondition() ? new int[42] : inData; // (1) // ... if (someOtherCondition()) { data = null; // (2) } } // ... } (1) Whether we use inData depends on someCondition(). It may be so that bar() is never called depending on someCondition() in the program at all. (2) data may never refer to 'static_array' after the constructor exits depending on someOtherCondition() The code above may not be using good coding practices and humans may see the bugs if there are any but only a slow (infinetely?) compiler can see through all the code. (I think @live will help with these cases.) Further, the support for "separate compilation" makes it impossible to see through function boundaries. Additionally, we don't want the compiler to force us to copy all stack variables just in case. In summary, you are right but the compiler cannot do anything about it in all cases and we wouldn't want it to spend infinite amount of time to try to determine everything. Ali
Re: dirEntries removes entire branches of empty directories
On 11/11/22 08:00, Ali Çehreli wrote: > It may have to do something with the performance of the hard disk. I meant "the reason you got a much better improvement" may have to do something with the performance differences of your hard disk and mine. Ali
Re: dirEntries removes entire branches of empty directories
On 11/11/22 05:13, kdevel wrote: > dmd -O compiled patched (see below!) version applied to /usr/bin on my > desktop > yields: > > ftw : 363 ms, 750 ÎŒs, and 5 [*] > dirEntries: 18 secs, 831 ms, 738 ÎŒs, and 3 [*] Great. I did not use -O with my test. It may have to do something with the performance of the hard disk. ftw wins big time. Being just a D binding of a C library function, its compilation should be quick too. >> entries ~= DirectoryEntry(entry, entry.getSize); >> } > > strace reports that entry.getSize invokes stat on the file a second > time. Isn't > the stat buf saved in the entry? That's my bad. entry.size is the cached version of the file size. > This also gives rise for a complication with symlinks pointing to the > directory > which contain them: > > $ pwd > /tmp/k/sub > $ ln -s . foo > $ ../direntrybenchmark . > std.file.FileException@8[...]/linux/bin64/../../src/phobos/std/file.d(1150): ./foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo: Too many levels of symbolic links So, ftw does not have that problem? Perhaps because of its default symlink behavior? There is also the more capable nftw, where the caller can specify some flags. And yes, there it is: FTW_PHYS If set, do not follow symbolic links. (This is what you want.) If not set, symbolic links are followed, but no file is reported twice. If FTW_PHYS is not set, but FTW_DEPTH is set, then the function fn() is never called for a directory that would be a descendant of itself. > -const dir = buildNormalizedPath("/home/ali/dlang"); > +const dir = buildNormalizedPath(args[1]); That one, and I had switched the arguments on the following call. One more example where string interpolation would be useful: writefln!"Ignoring type %s file: %s\n(See 'man nftw')b"( path, typeflag); I meant the arguments in the reverse order there. OT: And there is a 'b' character at the end of that format string which almost certainly appeared when I botched a Ctrl-b command in my editor. :) Ali
Re: dirEntries removes entire branches of empty directories
On 11/9/22 12:06, Ali Çehreli wrote: > I am using its sibling 'ftw' Now that we know that dirEntries works properly, I decided not to use ftw. However, ftw performs about twice as fast as dirEntries (despite some common code in the implementation below). I am leaving it here in case somebody finds it useful. (Why don't I put it on github then; ok, some day I will.) import core.sys.posix.sys.stat; import std.algorithm; import std.exception; import std.file; import std.path; import std.range; import std.string; // The Posix "file tree walker" function extern (C) int ftw(const char *dirpath, int function (const char *fpath, const stat_t *sb, int typeflag) fn, int nopenfd); enum TypeFlag { FTW_F, // regular file FTW_D, // directory // See 'man nftw' or /usr/include/ftw.h for the other values } struct DirectoryEntry { string name; ulong size; } struct WalkResult { DirectoryEntry[] entries; string[] emptyDirs; } WalkResult directoryWalk_ftw(string root) { WalkResult impl_() { // These have to be 'static' because ftw() does not allow us to pass a // context. And that's why this function must only be called from a // synchronized block. static DirectoryEntry[] entries; static string[] dirs; entries.length = 0; entries.assumeSafeAppend(); dirs.length = 0; dirs.assumeSafeAppend(); // This is the callback that ftw() uses. extern (C) int handler(const char *fpath, const stat_t *sb, int typeflag) { const path = fpath.fromStringz.idup; switch (typeflag) { case TypeFlag.FTW_F: entries ~= DirectoryEntry(path, sb.st_size); break; case TypeFlag.FTW_D: dirs ~= path; break; default: import std.stdio; writefln!"Ignoring type %s file: %s\n(See 'man nftw')b"( path, typeflag); break; } return 0; } // The tree walk will be faster up-to this "search depth" (See 'man nftw') enum nopenfd = 32; const ret = ftw(root.toStringz, , nopenfd); enforce(ret == 0, format!"Failed walking the directory tree at %s; error: %s"( root, ret)); string[] nonEmptyDirs = chain(entries.map!(e => e.name), dirs) .map!dirName .array .sort .uniq .array; sort(dirs); string[] emptyDirs = setDifference(dirs, nonEmptyDirs) .array; return WalkResult(entries.dup, emptyDirs); } synchronized { return impl_(); } } WalkResult directoryWalk_dirEntries(string root) { DirectoryEntry[] entries; string[] dirs; foreach (entry; dirEntries(root, SpanMode.depth)) { if (entry.isDir) { dirs ~= entry; } else { entries ~= DirectoryEntry(entry, entry.getSize); } } string[] nonEmptyDirs = chain(entries.map!(e => e.name), dirs) .map!dirName .array .sort .uniq .array; sort(dirs); string[] emptyDirs = setDifference(dirs, nonEmptyDirs) .array; return WalkResult(entries.dup, emptyDirs); } int main(string[] args) { import std.datetime.stopwatch; import std.stdio; import std.path; if (args.length != 2) { stderr.writefln!"Please provide the directory to walk:\n\n %s \n" (args[0].baseName); return 1; } const dir = buildNormalizedPath("/home/ali/dlang"); auto timings = benchmark!({ directoryWalk_ftw(dir); }, { directoryWalk_dirEntries(dir); })(10); writefln!("ftw : %s\n" ~ "dirEntries: %s")(timings[0], timings[1]); return 0; } Ali
Re: dirEntries removes entire branches of empty directories
On 11/9/22 11:30, Vladimir Panteleev wrote: > On Wednesday, 9 November 2022 at 19:05:58 UTC, Ali Çehreli wrote: >> Running the program shows no output; 'a' is not visited as a directory >> entry. > > That's not what happens for me: Does not happen for me today either. (?) I must have confused myself both with my actual program and with a trivial isolated program that I had written to test it. Unless others have seen the same behavior yesterday there is no bug here today. :p Ali "walks away with a confused look on his face"
Re: dirEntries removes entire branches of empty directories
On 11/9/22 11:05, Ali Çehreli wrote: > Can you think of a workaround to achieve that? Me, me, me! :) I've learned about the Posix function 'nftw' (but I am using its sibling 'ftw'). It was pretty easy to use but there is a quality issue there: They failed to support a 'void*' context for the user! You can walk the tree but can't put the results into your local context! Boo! I guess it was designed by someone who is happy with global variables. :) At least D makes it easy to guard access to module variables with 'synchronized', shared, etc. Ali
Re: dirEntries removes entire branches of empty directories
On 11/9/22 11:48, Imperatorn wrote: > That's not the behaviour I get in Windows. Windows users deserve it! :p (At least it is better in this case. :) ) > When I create the subdirectory, I see it even if it's empty struct DirIteratorImpl has different implementations for Windows, etc. Ali
dirEntries removes entire branches of empty directories
In case it matters, the file system is ext4. 1) Create a directory: mkdir deleteme and then run the following program: import std; void main() { foreach (e; dirEntries(absolutePath("./deleteme"), SpanMode.breadth)) { writeln(e.name); } } Understandably, the top level directory 'deleteme' will not be printed. 2) Make a sub-directory: mkdir deleteme/a Running the program shows no output; 'a' is not visited as a directory entry. 3) Create a file inside the sub-directory: touch deleteme/a/x Now the program will show 2 entries; the branch is accessible: /home/ali/d/./deleteme/a /home/ali/d/./deleteme/a/x Imagine a program that wants to make sure the directory structure is intact, even the empty directories should exist. Can you think of a workaround to achieve that? Do you think this is buggy behavior for dirEntries? Ali
Re: Passing a string by reference
On 11/8/22 04:53, Alexander Zhirov wrote: > On Tuesday, 8 November 2022 at 12:43:47 UTC, Adam D Ruppe wrote: >> Just use plain `string`. > > So it's always working with thick pointers? Yes, D's arrays are fat pointers. strings are arrays of immutable(char). >> nope, an object isn't created there at all. you should use `new C`. > > If I create just `A c`, then is it an empty pointer? Yes. Classes are reference types in D. Class variables are implemented as pointers. Their default value is null. Ali
Re: What's the correct way of creating an instance of class in D?
On 11/3/22 08:40, H. S. Teoh wrote: > D does not have the equivalent of C++'s allocating a class instance on > the stack. Not by default but we have two different ways, either may be discouraged: import std.typecons : scoped; import std.stdio; class C { int i; } void main() { // Either this: // auto c = scoped!C(); // Or this: scope c = new C(); writeln("If the address values are close, then the object is on the stack:"); writeln(); writeln(); } Ali
Re: Unit testing a function returning void
On 11/3/22 03:00, Bruno Pagis wrote: >void print() { > writeln("array = ", this.array); >} Similar to Paul Backus's program but I would try to avoid the file system for unit tests when possible. In this case, you can print into a sink, which can be useful in other ways as well: import std.stdio; class A { int[] a; this(int[] a) { this.a = a; } void toString(scope void delegate(in char[]) sink) const { import std.conv : text; sink("array = "); sink(this.a.text); // or this.a.to!string // The following alternative may be a little heavier weight: // import std.format : formattedWrite; // sink.formattedWrite!"array = %s"(this.a); } void print() { writeln(this); } } unittest { import std.file; A a = new A([1, 2]); import std.conv : text; assert(a.text == "array = [1, 2]"); } void main() {} toString is the textual representation of the object. If you don't want the same output for that purpose, you can use a different name from toString but you have to use an explicit "sink" but I really think the above is what you want. :) Ali
Re: save() feature for iota
On 11/3/22 04:58, Paul Backus wrote: > https://issues.dlang.org/show_bug.cgi?id=23453 Even though iterating over UTF value ranges don't make sense in general, they would work for some values including the ASCII range. Ali
Re: druntime thread (from foreach parallel?) cleanup bug
On 11/1/22 10:27, H. S. Teoh wrote: > Maybe try running Digger to reduce the code for you? Did you mean dustmite, which is accessible as 'dub dustmite ' but I haven't used it. My guess for the segmentation fault is that the OP is executing destructor code that assumes some members are alive. If so, the code should be moved from destructors to functions to be called like obj.close(). But it's just a guess... Ali
Re: CTFE in betterC needs the GC
On 10/29/22 20:41, arandomonlooker wrote: > string exampleCTFE(string a, string b) { > return a ~ b; > } Although you need that function only at compile time, it is an ordinary function that could be called at run time as well. The function needs GC for that concatenation in the general case. One way of solving your issue would be to change the function to a function template and pass the strings as template parameters (compile-time parameters): string exampleCTFE(string a, string b)() { return a ~ b; } which would require explicit function template instantiation: enum example = exampleCTFE!("A", "BCDE"); which would cause code bloat because exampleCTFE would be instantiated for every string combination that was used. For example, the following two uses would require two separate instantiations: enum example1 = exampleCTFE!("A", "BCDE"); enum example2 = exampleCTFE!("A", "BCDEX"); > int main() { I think you also need to specify main() as extern(C): extern (C) int main() { // ... } Ali
Re: ubyte + ubyte = int
On 10/26/22 14:19, Ali Çehreli wrote: >https://dlang.org/spec/type.html#integer-promotions Reading "Value Range Propagation" further down that link, I learned that e.g. masking 'decimal' with 0xf makes the code compile: return ((decimal & 0xf) + ubyte('0')); return ((decimal & 0xf) - ubyte(10) + ubyte('A')); Ali
Re: ubyte + ubyte = int
On 10/26/22 14:10, 0xEAB wrote: > I guess, this fancy behavior is inherited from C. Yes. It is called integer promotions: https://dlang.org/spec/type.html#integer-promotions (The next section is related as well.) > I know this is advanced stuff, but the compiler *could* even prove that > the calculation(s) won’t go beyond `ubyte.max`. Apparently it does not go that far but there is Value Range Propagation: https://www.digitalmars.com/articles/b62.html That article links to this forum post: https://www.digitalmars.com/d/archives/digitalmars/D/Value_Preservation_and_Polysemy_80224.html#N80293 Ali
Re: Replacing tango.text.Ascii.isearch
On 10/25/22 22:49, Siarhei Siamashka wrote: > Unicode is significantly simpler than a set of various > incompatible 8-bit encodings Strongly agreed. > I'm surely > able to ignore the peculiarities of modern Turkish Unicode The problem with Unicode is its main aim of allowing characters of multiple writing systems in the same text. When multiple writing systems are in play, conflicts and ambiguities will appear. > and wait for > the other people to come up with a solution for D language if they > really care. I solved my problem by writing an Alphabet hierarchy in the past. I don't like that code but it still works: https://bitbucket.org/acehreli/ddili/src/4c0552fe8352dfe905c9734a57d84d36ce4ed476/src/alphabet.d#lines-50 It handles capitalization, ordering, etc. I use it when preparing the Index section of the Turkish edition of "Programming in D": http://ddili.org/ders/d/ix.html One of the ambiguities is what came up on this thread: Should a word that starts with I (capital i) be listed under I (because it's Turkish) or under İ (because it's English)? So far, I am lucky because the only word that starts with I happens to be the English "IDE", so it goes under i (which appears as İ in the Turkish edition) and would make sense to a Turkish reader because a Turkish reader might (really?) accept it as the capital of ide. It's confusing but it seems to work. :) It doesn't matter. Life is imperfect and things will somehow work in the end. Ali
Re: Is "auto t=T();" not the same as "T t;"?
On 10/25/22 19:25, Salih Dincer wrote: > with static in main(): If 'static' makes a difference on your side as well, it is your turn to create a bug report. :) (Last time you discovered a bug, I was too quick to report it. :/) Ali
Re: Is "auto t=T();" not the same as "T t;"?
On 10/25/22 17:16, Salih Dincer wrote: > Excuse me, but they still write in purple prose about dynamic > array literature here! I've heard positive things about D's arrays from people who use D in production. Especially slices... > I've known D for more than 10 years, but the topic we're talking about > still seems strange to me. Your example makes it more complicated and potentially exposes a bug. > The explanations given are not enough for > me, I'm sorry. There may be a number of different concepts to list but I don't think there is anything inherently complicated with these topics (again, your example is more complicated). > Can anyone tell me what happens when I change the location of the > structure? What you mean is, you see different behaviour depending on struct X is nested or not. The difference is, nested structs carry a context pointer. This may be related to a bug for the different outputs that we see. > So the X structure must be in the stack when it is in > main(), and the following must be in the heap, right? To nit-pick: The struct is just a definition. Not the struct but its objects can be on the stack or on the heap. But yes, all objects you have are on the stack. > //void main() { So when you uncomment that line and comment-out the following main() line in the program, you see a different output. I tested: If you make X a 'static struct', then you see the same output. I think the difference is due to a bug. Ali
Re: auto scope question?
On 10/25/22 15:07, WhatMeWorry wrote: > auto screen = executeShell(cmdLine); > auto s; That can't work because there is no information to infer the type of 's'. Judging from the return type of getPath, perhaps it's string[]: string[] s; This is the question we should answer first: What should happen when executeShell fails? a) It is an error; the program should not continue. Then we can use 'enforce' (this is my way of coding): string[] getPath(string cmdLine) { import std.exception : enforce; auto screen = executeShell(cmdLine); enforce(screen.status == 0, format!"%s failed:\n%s"(cmdLine, screen.output)); writeln("screen.output = ", screen.output); auto s = screen.output.findSplit("REG_SZ"); writeln("s[0] = ", s[0]); writeln("s[1] = ", s[1]); writeln("s[2] = ", s[2]); return (s.split(';')); } b) It is not an error; getPath() should return empty array: string[] getPath(string cmdLine) { string[] result; auto screen = executeShell(cmdLine); if (screen.status != 0) { writeln(cmdLine, " failed"); return null; // <-- HERE (null converts to any array type) } else { // ... // Now, 'return' is where 's' is defined: return (s.split(';')); } } Ali
Re: Is "auto t=T();" not the same as "T t;"?
On 10/25/22 13:36, matheus wrote: > On Tuesday, 25 October 2022 at 20:12:25 UTC, Paul Backus wrote: >> Static arrays are value types. What that means is, when we say float[3], there are just 3 floats without any overhead. >> Dynamic arrays are reference types. That phrase can be confusing because we often use the terms "dynamic array" and "slice" interchangably. I find the following simpler to understand (can still be confusing): - Dynamic arrays are expandable arrays that are owned by the D runtime (the GC). Dynamic arrays don't have names. - The names (symbols) that we see in source code are slices that are references to elements of arrays. Such arrays can be static or dynamic. When we add an element to a slice that has no room (.capacity <= .length) then a fresh dynamic array is created from the copies of the elements of the slice. > if this is a case the generate more problem understanding this rules, I think all these array complexities are inherent. Other examples from two other languages that I know: - In C, arrays that are members of user-defined types are value types. Arrays that are parameters are reference types (pointer to the first element). Confusing. - In C++, std::vector is a value type, which would be copied if passed by value. So there came std::array, std::string_view, std::span, etc. to address value versus reference complexities. I don't think D could do anything better with arrays. They seem to work pretty well and are among the favorite features of many D programmers. Ali
Re: Is "auto t=T();" not the same as "T t;"?
On 10/25/22 13:12, Paul Backus wrote: > In order to create a copy of a static array Although .dup works for static arrays as well, you meant "dynamic array" and everyones knows it. :) > with its own block of > memory, separate from the original, you have to use the built-in `.dup` > method: > > ```d > int[] a = [1]; > int[] b = a.dup; Ali
Re: Is "auto t=T();" not the same as "T t;"?
On 10/25/22 11:23, Steven Schveighoffer wrote: >> Why do I say incorrect things like that? :) > You were right actually. As always! Now I'm confused. :o) Ali
Re: Is "auto t=T();" not the same as "T t;"?
On 10/25/22 11:01, Ali Çehreli wrote: > static arrays don't have .ptr to point > to any member. Why do I say incorrect things like that? :) Of course static arrays have .ptr as well but that always point to their own body of N elements. They own their elements... I move away from the keyboard now... :) > Static arrays are "just elements side by side." I still like that description though. Ali
Re: Is "auto t=T();" not the same as "T t;"?
On 10/25/22 10:54, Salih Dincer wrote: > So I don't understand why it causes problems with > dynamic arrays! So why is there nothing wrong with the static array in > the example below? The same rules as other uses of dynamic arrays... > //A[] a = [A.init];/* In that case, there is a single instance of [A.init]. All A.a members point to it through their .ptr .length members. > A[1] a = [A.init];//*/ In that case, there is still a single instance of [A.init], which gets copied to each A.a member because static arrays don't have .ptr to point to any member. Static arrays are "just elements side by side." In other words, there is no option but to copy to static arrays; they can't point to elements and they don't have any problem in this case. Ali
Re: Is "auto t=T();" not the same as "T t;"?
On 10/25/22 08:50, Andrey Zherikov wrote: > I'd like to tune default ctor but structs can't have custom one. > Adding a ctor with parameter seems a hack to me There is static opCall, which may be seen as a hack as well. :) The following all print the same thing now: import std.stdio; struct A { int[] i; } struct B { A[] a = [A.init]; static B opCall() { return B.init; } } void main() { auto b1 = B.init; b1.writeln; B b2 = B(); b2.writeln; B b3; b3.writeln; } > This fails in run time Not anymore with the above code. Ali
Re: Is "auto t=T();" not the same as "T t;"?
On 10/25/22 07:53, Adam D Ruppe wrote: > On Tuesday, 25 October 2022 at 13:51:30 UTC, Andrey Zherikov wrote: >> A[] a = [A.init]; > > This is a problem - this is referring to a static array instance, shared > across all copies of B. You almost certainly don't want this. Agreed. It should be fine when the elements are immutable as I've experimented with recently[1]: struct Xml { string beg; string end = "/>"; // Shared by all instances; // no allocation for some objects. // ... } > As for why B() and B.init are different here... i don't know, probably > some subtly of the compiler's implementation. I think it's a bug. Ali [1] https://youtu.be/0JL9uT_XGZE?t=4260s
Re: Supporting foreach (k, v; T.init) for a user-defined (container) type
On 10/24/22 14:26, Per Nordlöw wrote: What property of a container (type) `T` enables iteration as ```d foreach (k, v; T.init) { ... } ``` ? I thought it sufficed to define `T.byKeyValue` but its presence seem to have no effect. Another option is to use range functions where front() returns a Tuple. We have an esoteric feature where a tuple expands automatically in foreach loops: import std.typecons : tuple; import std.conv : to; import std.stdio : writeln; import std.range : take; struct S { size_t count; bool empty = false; auto front() { const key = count; const value = key.to!string; return tuple(key, value);// <-- HERE } void popFront() { ++count; } } void main() { foreach (k, v; S.init.take(10)) { writeln(k, ": ", v); } } Ali
Re: Find in assoc array then iterate
On 10/22/22 08:21, Kevin Bailey wrote: > his claim that there was no value. I think he was questioning the need for iterating from a point forward inside an unordered container. When the container is unordered, the elements that are accessed after a found element could be anything. I think that's the puzzling part in your question. > package main Here is my interpretation of Paul Backus's solution: module main; import std.stdio; void main() { int[string] m; m["key1"] = 7; m["key2"] = 8; auto iter = m.byKeyValue(); // Advance iterator iter.popFront(); // Preserve position auto iter2 = iter.save(); // Exhaust first iterator foreach (kv; iter) { writeln("iter: ", kv.key, " = ", kv.value); } // What does second iterator see? foreach (kv; iter2) { writeln("iter2: ", kv.key, " = ", kv.value); } } May print (because its unordered): iter: key2 = 8 iter2: key2 = 8 Ali
Re: Real simple question... for good programmers
On 10/22/22 14:53, WhatMeWorry wrote: > > > string[] tokens = userSID.output.split!isWhite; > writeln("tokens = ", tokens); Could you please show minimal compilable code that demonstrates the issue. I spent some time with some guesses but failed (to get my code to compile with std.array.split). Ali P.S. Sorry for also sending email.
Re: Find in assoc array then iterate
On 10/21/22 15:03, Kevin Bailey wrote: I'm trying to do this equivalent C++: unordered_map map; for (auto i = map.find(something); i != map.end(); ++i) ...do something with i... in D, but obviously with an associative array. It seems that it's quite easy to iterate through the whole "map", but not start from the middle. Am I missing something obvious (or not so obvious) ? Something like the following perhaps, which sorts the keys: import std; // Sorry :( void main() { auto m = iota(20).map!(i => tuple(i, format!"value_%s"(i))).assocArray; foreach (key; m.keys.sort.find(13)) { writeln(m[key]); } } Ali
Re: Catching C errors
On 10/19/22 09:47, data pulverizer wrote: > It's okay, I've found a work around. Do you simply check the return value? Ali
Re: Catching C errors
On 10/19/22 07:05, data pulverizer wrote: > I am calling code from a C API, and would like to know how to catch exit > errors If you are talking about the exit() Posix function, you can't do anything about that because its purpose is to cause "normal process termination". Ali
Re: warning LNK4255 - How to solve this warning
On 10/18/22 12:26, Hipreme wrote: > Is there any way to know which files produced this error or at least the > symbol names that are clashing? I'm totally helpless about this error. There is 'nm' on Posix systems that lists symbols in object files (including libraries and programs). Ali
Re: parallel is slower than serial
On 10/18/22 06:24, Guillaume Piolat wrote: > To win something with OS threads, you must think of tasks that takes on > the order of milliseconds rather than less than 0.1ms. > Else you will just pay extra in synchronization costs. In other words, the OP can adjust work unit size. It is on the official documentation but I also mention it on slide 72 of the section that starts at the following point: https://youtu.be/dRORNQIB2wA?t=1327 Ali
Re: Reading and wiping notes also adding more notes
On 10/17/22 22:40, Joel wrote: > I have two text fields. The one on the left has the whole text, new > stuff being added to the bottom. The one on the right has text I've been > wiping as I'm reading. I think this can be modelled as a string array and an index showing where the active part starts: import std; struct Notes { string[] whole; size_t activeIndex; void add(string line) { whole ~= line; } string[] activeText() { return whole[activeIndex..$]; } void wipeText() { ++activeIndex; } } void main() { auto input = [ "I went for a walk and fell down a hole.", "There was a D guy on the roof.", "That was a tricky problem!", ]; Notes notes; // add() to add() input.each!(line => notes.add(line)); // activeText() will show the active part // wipeText() will move forward } Ali
Re: probably a trivial question...
Changing the order of lines... On 10/13/22 16:43, WhatMeWorry wrote: > return s.split(';'); // single quotes That one is a single character and very lightweigth because it's just an integral value. You can't put more than one character within single quotes: ';x' // ERROR > return s.split(";"); // double quotes That one is a string, which is the equivalent of the following "fat pointer": struct Array_ { size_t length; char * ptr; } For that reason, it can be seen as a little bit more costly. 'length' happens to be 1 but you can use multiple characters in a string: ";x" // works (Aside: There is also a '\0' character sitting next to the ';' in memory so that the literal can be passed to C functions as-is.) Double-quoted strings have the property of escaping. For example, "\n" is not 2 characters but is "the newline character". > return s.split(`;`); // back ticks They are strings as well but they don't do escaping: `\n` happens to be 2 characters. There is also strings that start with q{ and end with }: auto myString = q{ hello world }; And then there is delimited strings that use any delimiter you choose: auto myString = q"MY_DELIMITER hello world MY_DELIMITER"; Some information here: http://ddili.org/ders/d.en/literals.html#ix_literals.string%20literal Ali
Re: Replacing tango.text.Ascii.isearch
On 10/5/22 13:40, torhu wrote: auto sw = StopWatch(); Either this: auto sw = StopWatch(AutoStart.yes); or this: auto sw = StopWatch(); sw.start(); Ali
Re: Remove elements without losing capacity
On 10/4/22 10:59, Riccardo M wrote: > The inherent reason for `remove` to cancel previous capacity and > requiring new allocations is exactly to prevent overwriting data that > could be owned by something else? Yes. A related topic is how the "end slice" never loses that capacity: void main() { auto a = [ 1, 2 ]; auto b = a; assert(a.capacity != 0); assert(b.capacity != 0); b.length--; assert(b.capacity == 0); assert(a.capacity != 0);// <-- Preserved } Aside: .capacity is an expensive operation that requires some levels of table lookups in the druntime. A data structure would benefit a lot if it kept its own capacity as a member variable. Ali
Re: rotate left an array
On 10/3/22 17:00, Paul Backus wrote: > On Monday, 3 October 2022 at 21:06:36 UTC, Ali Çehreli wrote: >> On 10/3/22 13:48, Andrey Zherikov wrote: >>> a "rotated view". >> >> Without indexes: >> >> import std.range : empty; >> >> auto rotatedView(R)(R range) >> in (!range.empty) >> { >> import std.range : chain, front, only, popFront; >> const fr = range.front; >> range.popFront(); >> return chain(range, only(fr)); >> } > > Tiny nitpick: this should use > > const fr = range.save.front; > > ...to ensure that `fr` is not invaliated or overwritten by the > subsequent call to range.popFront (e.g., think of File.byLine here). Good catch but I think what we want is a copy of the front element, at least for InputRanges (.save does not work for File.byLine :/). What is the generic way of copying an element? I wonder whether we have to use isSomeString to take care of all element types. Ali
Re: rotate left an array
On 10/3/22 13:48, Andrey Zherikov wrote: a "rotated view". Without indexes: import std.range : empty; auto rotatedView(R)(R range) in (!range.empty) { import std.range : chain, front, only, popFront; const fr = range.front; range.popFront(); return chain(range, only(fr)); } void main() { import std.algorithm : equal; int[] arr1 = [ 1, 2, 3, 4 ]; assert(arr1.rotatedView.equal([ 2, 3, 4, 1 ])); // Now this is getting a little expensive! :) assert(arr1 .rotatedView .rotatedView .equal([ 3, 4, 1, 2 ])); } Ali
Re: Stop writeln from calling object destructor
On 10/2/22 10:55, data pulverizer wrote: > On Sunday, 2 October 2022 at 17:28:51 UTC, data pulverizer wrote: >> Sorry I'll need to implement all the overloaded copy constructors and >> see if that fixes it. > > I've got it, something weird happened to my copy constructor. This was > my original attempt and was ignored (didn't run in the copy constructor): > > ``` > this(T)(ref return scope T original) > if(is(T == RVector!(Type))) > { > //... code ... > } > ``` I've just tested. That is used only for explicit constructor syntax: auto b = RVector!int(a);// templatized > > > But this now works: > > > ``` > this(ref return scope RVector!(Type) original) > { > //... code ... > } > ``` That one works for both syntaxes: auto b = RVector!int(a);// templatized auto c = a; // non-templatized Certainly confusing and potentially a bug... :/ > No idea why. `Type` is a template parameter of the object. Minor convenience: You can replace all RVector!(Type) with just RVector in the implementation of RVector because the name of the struct template *is* that specific instantiation of it: struct RVector(Type) { // RVector below means RVector!Type: this(ref return scope RVector original) { // ... } } Ali
Re: Stop writeln from calling object destructor
On 10/2/22 10:28, data pulverizer wrote: > On Sunday, 2 October 2022 at 17:19:55 UTC, data pulverizer wrote: >> Any reason why this could be? > What I noticed first in your original code was that it would be considered buggy because it was not considering copying. Every struct that does something in its destructor should either have post-blit (or copy constructor) defined or simpler, disallow copying altogether. That's what I did here: https://github.com/acehreli/alid/blob/main/cached/alid/cached.d#L178 @disable this(this); I think disabling copy constructor was unnecessary but I did that as well: @disable this(ref const(typeof(this))); The issue remains and bothers me as well. I think writeln copies objects because D disallows references to rvalue. We couldn't print rvalues if writeln insisted on 'ref'. Or, rvalues would be copied anyway if we used 'auto ref'. Hence the status quo... > Sorry I'll need to implement all the overloaded copy constructors and > see if that fixes it. The best solution I know is to disable copying and printing not the object but an explicit string representation of it: Added: @disable this(this); Added (there are better ways of doing the same e.g. using a 'sink' parameter): string toString() const { import std.format : format; return format!"id: %s"(id); } Called toString: writeln("MyObject: ", obj.toString); Ali
Re: Linker Error with Template Function
On 10/1/22 11:15, Kyle Ingraham wrote: > storing structs as > `void*` in a wrapper struct with information about their module and > identifier saved elsewhere. Perhaps unrelated but that part reminded me of the following discussion: https://forum.dlang.org/post/tfbn10$19nv$1...@digitalmars.com Ali
Re: How can I get the "owner" of a method?
On 9/30/22 14:11, solidstate1991 wrote: > extern (C) public int registerDDelegate(alias Func, That can be a lambda that takes ClassType. I wrote the following along with place holder as I assumed them to be: class C { string s; void foo() { import std.stdio : writeln; writeln("Look ma: It was ", s, " but I am using it in D!"); } } auto luaGetFromIndex(C)() { auto c = new C(); c.s = "created in Lua"; return c; } extern (C) int registerDDelegate(alias Func)() { import std.traits : Parameters; alias ClassType = Parameters!Func[0]; auto c = luaGetFromIndex!ClassType(); Func(c); return 0; } void main() { // Here: The lambda takes a C: registerDDelegate!((C c) => c.foo); } Ali
Re: Interfacing with basic C++ class
On 9/29/22 01:28, Riccardo M wrote: > if one should > slightly rearrange C++ code as well. Right. Additionally, the order of members must match (I am pretty sure, which means I am not :p). > I am a recent addition to D > language :) Welcome! :) > Do you know that this is documented somewhere? The examples in the > official docs are rather limited Manu Evans said at DConf 2022 that the documentation is very lacking compared to actual capability. People who know should update the docs. Ali