Re: Query for -dip1000
On Monday, February 11, 2019 3:23:25 AM MST Seb via Digitalmars-d-learn wrote: > On Monday, 11 February 2019 at 09:29:13 UTC, Jonathan M Davis > > wrote: > > On Sunday, February 10, 2019 1:04:29 PM MST Per Nordlöw via > > > > Digitalmars-d- learn wrote: > >> [...] > > > > A quick grep of Phobos shows a version(DIP1000) block in > > std/typecons.d, which appears to be used to make it so that a > > particular unittest block is only compiled in when -dip1000 is > > used, so it looks like there's a version identifier for it. > > > > - Jonathan M Davis > > That one has been added manually: > > https://github.com/dlang/phobos/blob/master/dip1000.mak > > The detection would have been better... Honestly, having an explicit version is far better than trying to detect it in an ad-hoc manner. It's actually guaranteed to be right in that case, whereas ad-hoc tests are more likely to have problems - especially if they're around for a while, and things change that weren't anticipated when the code was written. So, I'd actually argue that manually setting it as part of the build was a better idea than trying to detect it, but if it's manually set as part of the build instead of being built into the compiler, then it doesn't help anyone else. Though honestly, it seems to me that having version identifiers for transitional compiler flags like that is probably a good idea, since it makes transitioning code easier. The best that we can do otherwise is generally using __VERSION__, and that only works once the change is the default. - Jonathan M Davis
Re: Query for -dip1000
On Sunday, February 10, 2019 1:04:29 PM MST Per Nordlöw via Digitalmars-d- learn wrote: > Is there a way to query if the -dip1000 flag has been passed to > the compiler? I need it for enabling certain DIP-1000 escape > analysis tests only when -dip1000 has been passed. > > For instance > > static assert(!__traits(compiles, { > char[] f() > { > char[2] x; > return x[].splitterASCII!(_ => _ == ' > ').front; > } > })); > > at > > https://github.com/nordlow/phobos-next/blob/bd2fe42978aab2313977042c858d77 > c5766538e8/src/splitter_ex.d#L110 > > Or do I have to write a trait myself? A quick grep of Phobos shows a version(DIP1000) block in std/typecons.d, which appears to be used to make it so that a particular unittest block is only compiled in when -dip1000 is used, so it looks like there's a version identifier for it. - Jonathan M Davis
Re: dirEntries within static foreach: memory.d(827): Error: fakePureErrno cannot be interpreted at compile time, because it has no available source code
On Sunday, February 10, 2019 5:19:02 PM MST kdevel via Digitalmars-d-learn wrote: > I am trying to get this code compiled: > > ```TemplateStore.d > module TemplateStore; > import std.path; > import std.conv; > import std.file; > > immutable string[string] template_map; > > static this () > { > static foreach (f; dirEntries (``, `*.html`, > SpanMode.shallow)) { >pragma (msg, `reading template <` ~ f ~ ">"); >template_map[f] = import (f); > } > } > ``` > > dmd v2.082.0 says > > ...linux/bin64/../../src/druntime/import/core/memory.d(827): > Error: fakePureErrno cannot be interpreted at compile time, > because it has no available source code > Error: invalid foreach aggregate > Error: invalid foreach aggregate > > If I use an immutable array of file names instead of dirEntries > the code compiles, but I don't want to update that array each > time a new template file is added. > > As a workaround I wrote a helper which writes the quoted > filenames comma-separated into a file named `LS` using this > fragment: > > foreach (f; dirEntries (``, `*.html`, SpanMode.shallow)) >writefln ("`%s`,", f); > > Then I try to convince the dmd compiler to read LS and use its > content as initializer for the immutable array template_files: > > immutable LS = import (`LS`); > pragma (msg, `LS = <` ~ LS ~ `>`); > immutable template_files = [ >mixin(LS) > ]; > > dmd now says (1) if the list in LS has a trailing comma: > > TemplateStore.d-mixin-13(26): Error: expression expected, not > End of File > > or (2) if the list has no trailing comma: > > TemplateStore.d-mixin-13(13): Error: Using the result of a > comma expression is not allowed > TemplateStore.d-mixin-13(14): Error: Using the result of a > comma expression is not allowed > TemplateStore.d-mixin-13(15): Error: Using the result of a > comma expression is not allowed > > > What can I do about it? Nothing. You can't call C functions during CTFE, because the compiler doesn't have their source code, and all functions that interact with the filesystem have to ultimately call C functions. So, you can't use something like dirEntries with CTFE. The only way that you can do anything along the lines of reading files during CTFE is to use string imports to insert the text of a file directly into the module. - Jonathan M Davis
Re: Should D file end with newline?
On Sunday, February 10, 2019 2:06:50 AM MST Cym13 via Digitalmars-d-learn wrote: > On Sunday, 10 February 2019 at 02:12:43 UTC, Jonathan M Davis > > wrote: > > On Saturday, February 9, 2019 2:19:27 PM MST Victor Porton via > > > > Digitalmars- d-learn wrote: > >> ISO C++ specifies that the C++ file must end with a newline. > >> > >> Should D file end with newline, too? > > > > No, there is no need to end D files with a newline. I would > > guess that the vast majority of D files end with a closing > > brace. I just looked at a bunch of files in the standard > > library for the heck of it, and almost all of the ones I looked > > at ended with a closing brace. And those that didn't ended with > > something like an enum declaration and not a newline. > > Personally, I don't leave newlines at the end of files, because > > it looks messy. I don't even recall doing that in C++, though I > > do recall that there supposedly be a rule about it. It seems > > like a pretty bizarre requirement to me, but regardless, I'm > > quite sure that D does not have that requirement. > > > > - Jonathan M Davis > > If you used a text editor or IDE to write that final closing > brace then I'm pretty confident it does add the newline character > at the end. That won't result in an empty line on display. Try > using an hex editor to check if you're curious. I use (g)vim, which I would expect to show anything like trailing newlines. It usually shows everything, including rendering control characters and the like in a way that you know exactly what's there. Opening up std/algorithm/mutation.d in vim as an example, it clearly ends in a closing brace with no trailing newline. However if I feed it into hexdump ... 00158f0 2020 6373 706f 2865 7865 7469 2029 7266 0015900 6565 7328 702e 7274 3b29 7d0a 000a 001590d hexdump shows a newline followed by a null character followed by a newline after the carriage return. So, it does indeed look like extra junk is there after the data in the file, and surprisingly, vim doesn't showing it (or anything indicating that it's there). I don't know why any of that would be there, since it seems pointless me, but it is there in std/algorithm/mutation.d. On the other hand, if I open up std/datetime/systime.d with hexdump, it shows 007f8b0 0a7d 2020 2020 2020 2020 0a7d 2020 2020 007f8c0 0a7d 0a7d 007f8c4 so it actually ends on a closing braces. So, maybe some text editors shove extra junk on the end and others don't? I don't know. Either way, I find it very odd that vim doesn't show anything after the closing brace when it's there. Both of those files show a closing brace as their last character when opened in vim. Looking quickly at some of my personal projects, I don't see any files which end with anything other than a closing brace according to either vim or hexdump. And since all of those were created with (g)vim, I'd say that vim does not put those extra characters on the end (though it will allow them and otherwise ignore them). That also makes it clear that no newline or any other special sequence of characters is required at the end of a .d file, because all of those files work just fine with their last character being a closing brace. Curiously, if I create a .cpp or .c file with vim and have it end with a curly brace, vim _does_ append a newline followed by a null character followed by a newline at the end of the file. So, I guess that vim looks at the extension and realizes that C/C++ has such a requirement and takes care of it for you, but it does not think that .d files need them and adds nothing extra for them. It doesn't add anything for a .txt file when I tried it either. In any case, if your text editor happens to insert those extra characters at the end of a .d file, then they may end up there, but given what hexdump says and what dmd accepts, I can verify that they aren't actually required for .d files. - Jonathan M Davis
Re: Should D file end with newline?
On Saturday, February 9, 2019 2:19:27 PM MST Victor Porton via Digitalmars- d-learn wrote: > ISO C++ specifies that the C++ file must end with a newline. > > Should D file end with newline, too? No, there is no need to end D files with a newline. I would guess that the vast majority of D files end with a closing brace. I just looked at a bunch of files in the standard library for the heck of it, and almost all of the ones I looked at ended with a closing brace. And those that didn't ended with something like an enum declaration and not a newline. Personally, I don't leave newlines at the end of files, because it looks messy. I don't even recall doing that in C++, though I do recall that there supposedly be a rule about it. It seems like a pretty bizarre requirement to me, but regardless, I'm quite sure that D does not have that requirement. - Jonathan M Davis
Re: Is it possible to modify shared struct array in a function.
On Friday, February 8, 2019 4:27:44 AM MST Eduard Staniloiu via Digitalmars- d-learn wrote: > On Friday, 8 February 2019 at 06:55:15 UTC, Jerry wrote: > > On Friday, 8 February 2019 at 04:51:08 UTC, Sudhi wrote: > >> On Friday, 8 February 2019 at 04:30:23 UTC, Arun > >> > >> Chandrasekaran wrote: > >>> On Friday, 8 February 2019 at 04:13:39 UTC, Sudhi wrote: > [...] > >>> > >>> Works fine for me with DMD64 D Compiler v2.083.1. > >>> https://run.dlang.io/is/RRM8GU > >> > >> My example code was wrong. Below is the right one. > >> > >> struct Company > >> { > >> > >> string name; > >> string location; > >> > >> } > >> > >> struct Racks > >> { > >> > >> int number; > >> int location; > >> > >> } > >> > >> struct Metadata > >> { > >> > >> string name; > >> Company[] companies; > >> Racks[] racks; > >> > >> } > >> > >> struct Item > >> { > >> > >> Metadata[] met; > >> int count; > >> > >> } > >> > >> shared (Item) item; > >> > >> void main() > >> { > >> > >>updateMetadata(); > >> > >> } > >> > >> void updateMetadata() > >> { > >> > >>Company company; > >>company.name = "Hello"; > >>company.location = "Bangalore"; > >>item.met.companies ~= company; > >>import std.stdio: writeln; > >>writeln(item); > >> > >> } > >> > >> https://run.dlang.io/is/iem0PY > > > > You have to cast away shared: > > > > auto loc_item = cast(Item) item; > > loc_item.met ~= m; > > item = cast(shared) loc_item; > > > > Just to be clear, this is not threadsafe and require a mutex if > > you do this other than as init in main. > > You do not need to cast away shared. You had a couple of issues > with your `updateMetadata()` function. > > First of, `met` is an array, so you need to index it: your code > `item.met.companies ~= company` becomes `item.met[0].companies ~= > company`. This will compile, but throw a range error because you > don't have any `Metadata` object in your `met` array. > > I have typed below the revised form of your function > > ``` > void updateMetadata() > { > // create a Company instance. This must be shared > shared Company company; > company.name = "Hello"; > company.location = "Bangalore"; > > // create a shared Metadata instance > shared Metadata m; > m.name = "m"; > > // append m to the array of meta > item.met ~= m; > // append the company to the array of companies, for a given > meta > item.met[0].companies ~= company; > > import std.stdio: writeln; > writeln(item); > } > ``` > > The working version is at https://run.dlang.io/is/RvRKrU > > Cheers, > Edi Honestly, the fact that that code compiles is a bug. You're not supposed to be able to modify shared objects in a manner which isn't guaranteed to be atomic, because it's not thread-safe. The compiler catches it in a number of places, but there are many where it currently doesn't. But regardless of whether the compiler allows such mutation, a mutex (or similar protection mechanism) needs to be used in order to make the code thread-safe. - Jonathan M Davis
Re: Singleton in Action?
On Sunday, February 3, 2019 2:41:48 AM MST Ron Tarrant via Digitalmars-d- learn wrote: > On Saturday, 2 February 2019 at 19:40:25 UTC, Andre Pany wrote: > > https://rosettacode.org/wiki/Singleton#D > > Do you know if this is for a current version of D? The compiler > is choking on the import statements, complaining that it can't > read std/thread.d and std/c/time.d I don't recall std.thread ever existing, and std.c.time hasn't been around for a while. Thread is in core.thread, and all of the C bindings for standard C and OS APIs are supposed to be in druntime. So, the equivalent to C's time.h would be core.stdc.time. - Jonathan M Davis
Re: Implement Interface Using Super
On Monday, January 28, 2019 10:41:55 PM MST Meta via Digitalmars-d-learn wrote: > On Monday, 28 January 2019 at 22:17:56 UTC, Steven Schveighoffer > > wrote: > > On 1/28/19 3:28 PM, Jonathan Levi wrote: > >> On Sunday, 27 January 2019 at 09:31:46 UTC, bauss wrote: > >>> On Sunday, 27 January 2019 at 05:37:57 UTC, Jonathan Levi > >>> > >>> wrote: > This works in LDC *but not* DMD? > . . . > Is this a bug in DMD *or* in LDC? > >>> > >>> There is no bug here. > >> > >> So... LDC is the one that is bugged? > > > > Yeah, that's odd. It should be the same result, as they both > > have the same semantics for the front end. > > > > I'll defer to an LDC developer to answer that, but in truth, it > > really should be the way LDC implements it, even if that's not > > how the language spec is. > > > >> I think it would have been nice to have a way of explicitly > >> use the super method to implement an interface without having > >> to rewrite the whole signature. I thought I remember seeing a > >> way once, but I must have been dreaming. > > > > I agree. > > > > BTW, the typeof(super) requirement is super-annoying. alias x = > > super.x; is clear, I don't see why we need to specify > > typeof(super) in this context at least. > > > > -Steev > > It's because aliases do not support context pointers, I'm pretty > sure. Yeah. It would be like trying to do something like alias x = this.x; As it stands, I believe that super is always either used as a function call to the constructor or to mean the this pointer for the base class. I don't think that it ever means the type of the base class - just like this never means the type of the current class or struct. And their usage is pretty much identical. They're both either used for calling a constructor or for accessing the pointer/reference of the object. It's just that one of them is for the current class or struct, whereas the other is for a base class of the current class. The only difference in syntax that I can think of between them at the moment is that this is also used to name constructors when they're declared, whereas super is not used in that sort of way (since any constructor that would be referenced by super would be declared with this, not super). - Jonathan M Davis
Re: opEquals() non-standard return type
On Wednesday, January 23, 2019 8:19:06 AM MST Jacob Shtokolov via Digitalmars-d-learn wrote: > Hi, > > I'm trying to check whether it's possible to implement Python's > SQLAlchemy-like query syntax in D, but I get stuck a bit. > > Here is a simple example of what I want to achieve: > > ``` > auto result = User.filter(User.id == 10); > result = User.filter(User.name == "John"); > result = User.filter(User.age > 18); > ``` > > Expressions like `User.id == 10`, `User.age > 18`, etc. should > return a struct instead of a bool (let's call it `struct > BinaryExpression`). > > So I'm making the two versions of opEquals: one returns a > BinaryExpression, and the second - a boolean value. > > However, when I want to use the same expression for the `if` > operator, the compiler cannot decide what function to call and > shows an error: "overloads bool(int b) and BinaryExpr!int(int b) > both match argument list for opEquals". > > > I'm wondering, is that possible to declare multiple versions of > opEquals() and evaluate them in the different places depending on > return type? > > Here is my test code to check: https://run.dlang.io/is/yTFHWp > Gist: > https://gist.github.com/run-dlang/67ec42ca73d56d310e8ae765fabede69 > > Thanks! D's operator overloading is specifically designed around the idea that overloaded operators are supposed to act like the operators on the built-in types and that they _not_ be used for building syntax. opEquals is supposed to only return bool. If you attempt to make it return pretty much anything else, you're begging for trouble. But regardless of the specifics of operator overloading in D, D does not support overloading _any_ functions on the return type. Overloading is only done based an a function's arguments. You've declared two overloads with the exact same types for all of their parameters such that they only differ by their return type, and you can't do that in D. - Jonathan M Davis
Re: How to ensure string compatibility In D?
On Wednesday, January 23, 2019 5:42:55 AM MST FrankLike via Digitalmars-d- learn wrote: > On Wednesday, 23 January 2019 at 10:44:51 UTC, Jonathan M Davis > > wrote: > > On Tuesday, January 22, 2019 2:49:00 PM MST bauss via > > Digitalmars-d-learn wrote: > > > > toUTFz is the generic solution. toStringz exists specifically > > Error: template std.utf.toUTFz cannot deduce function from > argument types !()(string), candidates are: > E:\D\DMD2\WINDOWS\BIN\..\..\src\phobos\std\utf.d(3070): > std.utf.toUTFz(P) As the documentation shows, toUTFz requires a target type just like std.conv.to does. toUTF16z is a convenience wrapper around toUTFz which specifies the target type as const(wchar)*. > I have solved the problem in this way: > > import core.sys.windows.windows; > import std.stdio; > import std.string; > import std.conv; > > void main() > { > autostrA_Z ="CD"w; > auto type = GetDriveType(tos(to!wstring(strA_Z[0])~":\\")); > writeln(to!wstring(strA_Z[0])~" is ",type); > } > > private auto tos(T)(T str) > { > version (ANSI) > { > writeln("ANSI"); > return cast(const(char)*)(str); > } > else > { > writeln("Unicode"); > return cast(const(wchar)*)(str); > > } > } > > Thanks. std.conv.to will allow you to convert between string and wstring, but for calling C functions, you still need the strings to be zero-terminated unless the function specifically takes an argument indicating the number of characters in the string. Strings in D are not zero-terminated, so std.conv.to is not going to produce strings that work with C functions. std.conv.to and std.utf.toUTFz solve different problems. Also, strings of char in D are UTF-8, _not_ ANSI, so passing them to any of the A functions from Windows is not going to work correctly. If you want to do that, you need to use toMBSz and fromMBSz from std.windows.charset. But really, there's no reason at this point to ever use the A functions. There are frequently issues with them that the W functions don't have, and the W functions actually support Unicode. The only real reason to use the A functions would be to use an OS like Windows 98 which didn't have the W functions, and D doesn't support such OSes. So, I would strongly discourage you from doing anything with the A functions, let alone trying to write your code so that it uses either the A or W functions depending on some argument. That's an old Windows-ism that I wouldn't even advise using in C/C++ at this point. It's just begging for bugs. And since D doesn't have the macros for all of the various Windows functions for swapping between the A and W versions of the functions like C/C++ does, you have to explicitly call one or the other in D anyway, making it really hard to call the wrong one (unlike in C/C++, where screwing up how your project is compiled can result in accidentally using the A functions instead of the W functions). This really sounds like you're trying to duplicate something from C/C++ that doesn't make sense in D and really shouldn't be duplicated in D. - Jonathan M Davis
Re: How to ensure string compatibility In D?
On Tuesday, January 22, 2019 2:49:00 PM MST bauss via Digitalmars-d-learn wrote: > On Tuesday, 22 January 2019 at 19:14:43 UTC, Jonathan M Davis > > wrote: > > On Tuesday, January 22, 2019 12:05:32 PM MST Stefan Koch via > > > > Digitalmars-d- learn wrote: > >> On Tuesday, 22 January 2019 at 16:47:45 UTC, FrankLike wrote: > >> > On Tuesday, 22 January 2019 at 16:18:17 UTC, Adam D. Ruppe > >> > > >> > wrote: > >> >> Use "mystring"w, notice the w after the closing quote. > >> > > >> > Or toStringz is not work like c_str() in C++? > >> > >> stringz creates a char* > >> but you need a wchar* > > > > std.utf.toUTF16z or toUTFz can do that for you, though if your > > string is already a wstring, then you can also just concatenate > > '\0' to it. the big advantage toUTF16z is that it will also > > convert strings of other character types rather than just > > wstrings. So, you can write your program using proper UTF-8 > > strings and then only convert to UTF-16 for the Windows stuff > > when you have to. > > > > https://dlang.org/phobos/std_utf.html#toUTF16z > > https://dlang.org/phobos/std_utf.html#toUTFz > > > > - Jonathan M Davis > > Is there a reason we cannot implement toStringz like: > > immutable(TChar)* toStringz(TChar = char)(scope const(TChar)[] s) > @trusted pure nothrow; > // Couldn't find a way to get the char type of a string, so > couldn't make the following generic: > immutable(char)* toStringz(return scope string s) @trusted pure > nothrow; > immutable(wchar)* toStringz(return scope wstring s) @trusted pure > nothrow; > immutable(dchar)* toStringz(return scope dstring s) @trusted pure > nothrow; toUTFz is the generic solution. toStringz exists specifically for UTF-8 strings, and it exists primarily because it attempts to avoid actually appending or allocating to the string by checking to see if there's a null character after the end of the string (which is done, because that's always the case with string literals). If you don't care about it trying to avoid that allocation, then there arguably isn't much point to toStringz, and you might as well just to (str ~ '\0').ptr - Jonathan M Davis
Re: How to ensure string compatibility In D?
On Tuesday, January 22, 2019 12:05:32 PM MST Stefan Koch via Digitalmars-d- learn wrote: > On Tuesday, 22 January 2019 at 16:47:45 UTC, FrankLike wrote: > > On Tuesday, 22 January 2019 at 16:18:17 UTC, Adam D. Ruppe > > > > wrote: > >> Use "mystring"w, notice the w after the closing quote. > > > > Or toStringz is not work like c_str() in C++? > > stringz creates a char* > but you need a wchar* std.utf.toUTF16z or toUTFz can do that for you, though if your string is already a wstring, then you can also just concatenate '\0' to it. the big advantage toUTF16z is that it will also convert strings of other character types rather than just wstrings. So, you can write your program using proper UTF-8 strings and then only convert to UTF-16 for the Windows stuff when you have to. https://dlang.org/phobos/std_utf.html#toUTF16z https://dlang.org/phobos/std_utf.html#toUTFz - Jonathan M Davis
Re: Compiling to 68K processor (Maybe GDC?)
On Monday, January 21, 2019 10:08:23 AM MST Johan Engelen via Digitalmars-d- learn wrote: > On Saturday, 19 January 2019 at 17:45:41 UTC, Patrick Schluter > > wrote: > > Afaict NULL pointer derefernecing must fault for D to be > > "usable". At least all code is written with that assumption. > > Dereferencing `null` in D is implementation defined > (https://dlang.org/spec/arrays.html#pointers). > > For LDC, dereferencing `null` invokes Undefined Behavior [1]. > However, the compiler does try to be a little friendly towards > the programmer. UB includes just ignoring the dereference, but if > you are blatantly dereferencing `null` with optimization enabled, > the compiler generates a `ud2` instruction for you: > https://d.godbolt.org/z/5VLjFt > > -Johan > > [1] Now I am not quite sure yet whether Undefined Behavior is > part of the set of behaviors allowed to choose from for > Implementation Defined behavior. ;-) It is my understanding that Walter specifically chose the term "implementation defined" rather than "undefined," because undefined behior is not allowed, and that page you linked to supports that in that it lists "implementation defined" and "undefined" separately when talking about the behavior of dereferencing pointers. But you would have to discuss it with Walter to know exactly what he meant. The spec really should define those terms somewhere, but I doubt that it does. I haven't read through the spec in much detail recently though, so maybe it's in there somewhere. - Jonathan M Davis
Re: Compiling to 68K processor (Maybe GDC?)
On Saturday, January 19, 2019 10:45:41 AM MST Patrick Schluter via Digitalmars-d-learn wrote: > On Saturday, 19 January 2019 at 12:54:28 UTC, rikki cattermole > > wrote: > > On 20/01/2019 1:38 AM, Edgar Vivar wrote: > >> Hi, > >> > >> I have a project aiming to old 68K processor. While I don't > >> think DMD would be able for this on the other hand I think GDC > >> can, am I right? > >> > >> If yes would be any restriction of features to be used? Or the > >> compiler would be smart enough to handle this properly? > >> > >> Edgar V. > > > > Potentially. > > > > D is designed to only work on 32bit+ architectures. The 68k > > series did have 32bit versions of them. > > > > After a quick check it does look like LDC is out as LLVM has > > not yet got support for M68k target. Which is unfortunate > > because with the -betterC flag it could have pretty much out of > > the box worked. Even if you don't have most of D at your > > disposal e.g. classes and GC (but hey old cpu! can't expect > > that). > > > > I have no idea about GDC, but the -betterC flag is pretty > > recent so its support may not be what you would consider first > > class there yet. > > At least 68030 (or 68020+68851) would be necessary for proper > segfault managing (MMU) and an OS that uses it. Afaict NULL > pointer derefernecing must fault for D to be "usable". At least > all code is written with that assumption. For @safe to work properly, dereferencing null must be @safe, which means more or less means that either it results in a segfault, or the compiler has to add additional checks to ensure that null isn't dereferenced. The situation does get a bit more complicated in the details (e.g. calling a non-virtual member function on a null pointer or reference wouldn't segfault if the object's members are never actually accessed, and that's fine, because it doesn't violate @safe), but in general, either a segfault must occur, or the compiler has to add extra checks so that invalid memory is not accessed. At this point, AFAIK, all of the D compilers assume that dereferencing null will segfault, and they don't ever add additional checks. If an architecture does not segfault when dereferencing null, then it will need special handling by the compiler, and I don't think that ever happens right now. So, if D were compiled on such an architecture, @safe wouldn't provide the full guarantees that it's supposed to. - Jonathan M Davis
Re: Deprecation: foreach: loop index implicitly converted from size_t to int
On Friday, January 18, 2019 8:34:22 AM MST Michael via Digitalmars-d-learn wrote: > On Friday, 18 January 2019 at 13:29:29 UTC, Adam D. Ruppe wrote: > > On Friday, 18 January 2019 at 12:27:17 UTC, Michael wrote: > >> This, to be, looks like quite the explicit conversion, no? > > > > Yeah, I agree. But the language is silly. I just leave the type > > out of foreach and explicitly cast it inside the body. > > Thank you all for the concise explanations and suggestions, I > think that's fairly straightforward. I thought perhaps I was > doing the sensible thing of dealing with the conversion inside > the foreach statement, but I guess not! Well, you were really doing the equivalent of simply declaring a variable without a cast. e.g. int i = arr.length; rather than int i = cast(int)arr.length; In general, if the compiler treated giving the foreach variable an explicit type as being a cast, it would make it really easy to screw up and unknowingly give a different type than the actual type of the values and end up with an invisible cast, which could cause subtle bugs. IIRC, the only case where foreach treats giving an explict type as anything like a cast is when you're iterating over a string type, and you give a character type different from the character type of the string. In that case, it actually decodes the string from one Unicode encoding and encodes it in the other. Whether the language should have done that rather than requiring that a library solution be used is debatable (I believe that it far predates Phobos having the Unicode handling that it does now), but at least it can't result in stuff like silent truncation. Worst case, it has a silent performance hit, or you get an unexpected UnicodeException at runtime due to invalid Unicode. - Jonathan M Davis
Re: Alternative to Interfaces
On Friday, January 18, 2019 8:08:47 AM MST Kagamin via Digitalmars-d-learn wrote: > On Friday, 18 January 2019 at 00:08:00 UTC, 1001Days wrote: > > It works, but I have two questions regarding its efficacy: is > > it viable in the long run, and is it now possible to use > > delegates without the GC? > > GC is just a handy memory management approach, it even works for > C and C++, (example: gcc), nothing in D needs GC if you manage > memory in a different way. In fact there are D libraries that > rely solely on manual memory management. Yes, but some D features will use the GC, and you can't really stop that aside from simply not using those features. The list of such features is short, but delegates are on it. scope will get around the allocations in some cases, but in general, if you use delegates, you're going to allocate with the GC. There are alternatives to using delegates which will get you similar behavior allocating (e.g. functors), but the allocations that happen for delegates and lambdas is one of the biggest reasons that some folks avoid std.algorithm and complain that it allocates. That's what happens when you pass stuff that the compiler decides has to have closures allocated for it. Completely avoiding the GC with D is possible, but it tends to require that you be very careful and have a good understanding of where D needs to use the GC to do what it does (though the fact that we now have @nogc, and it screams at you if the code allocates does help you catch GC usage when you didn't realize that it was there). - Jonathan M Davis
Re: Runtime heterogeneous collections?
On Thursday, January 17, 2019 1:21:41 AM MST Dukc via Digitalmars-d-learn wrote: > On Thursday, 17 January 2019 at 02:27:20 UTC, Neia Neutuladh > > wrote: > > 1. Make a wrapper class. Now you can store Object[], or you can > > make a > > base class or base interface and use that. > > 2. Use Variant, which can wrap anything, or the related > > Algebraic, which > > can wrap a fixed collection of types. > > 3. Use an union. However, only do this if you always know from > outside what type of data is stored in each node. If you need to > memoize the type of data for each node, better resort to 1. or 2. Variant types are really just user-friendly wrappers around unions. So, pedantically, using a variant type such as Variant or Albegbraic and using a union are fundamentally the same thing, though obviously, the actual usage in terms of the code that you write is not the same, since if you use a union directly, you have to deal with the union directly (including figuring out how to know which type the union currently holds), whereas with a Variant, you're using its API rather than dealing with the union directly. In general, it's probably better to use Variant rather than union simply because Variant deals with the type safety for you. - Jonathan M Davis
Re: Compile time opAssign/@property constraints
On Friday, January 4, 2019 4:50:30 AM MST Jacob Shtokolov via Digitalmars-d- learn wrote: > On Friday, 4 January 2019 at 11:41:59 UTC, Simen Kjærås wrote: > > The thing is, compile-time tests like static if and static > > assert can only test values that are known at compile-time, and > > are for the most part useful only in templates. > > Thanks for this answer! That's sad to hear. > But, is there anything to do with CTFE? Can it help somehow in > such situation? CTFE is the compile-time evaluation of functions. You're calling a function at compile time. How the function works is basically the same as how it works at runtime. There are some caveats because of how the CTFE engine works (e.g. pointer arithmetic isn't legal at compile time), but the function itself is called normally. Something like a static assertion is run when the function itself is compiled - which must happen before that function is used during CTFE. So, you can do something like auto foo(int i) { static assert(someFunc() == 42); ... } but you can't do something like auto foo(int i) { static assert(someFunc() == i); ... } because that would be mixing compile time and runtime stuff. Even if foo is called at compile time, it's compiled before it's called, and the static assertion is part of its compilation process, not part of running it, and runtime variables aren't available when the function is being compiled. So, if you did auto foo(int i) { assert(someFunc() == i); ... } and then called foo with CTFE, then that assertion would be run as part of running foo just like it would be at runtime, but a static assertion wouldn't make sense. CTFE doesn't fundamentally change what is a compile-time and what is a runtime constructs. It just allows functions to be called at compile time so that you can do stuff like initialize values that are generated at compile time. Unfortunately, the wiki seems be down right now, but once it's back up, I suggest that you read https://wiki.dlang.org/User:Quickfur/Compile-time_vs._compile-time IIRC, it's still a work in progress, but it should give you a much clearer idea of how CTFE fits into things. - Jonathan M Davis
Re: DIP 1000 and classes
On Thursday, January 3, 2019 3:28:35 AM MST Nordlöw via Digitalmars-d-learn wrote: > How does DIP 1000 treat the lifetime scoped class parameters and > containers of classes? scope isn't transitive, and putting an object inside a container would be escaping it, which would violate scope. So, you could have a container that was scope, but you couldn't put anything that's scope inside of it. - Jonathan M Davis
Re: Qualified class opEquals()
On Tuesday, December 25, 2018 7:27:39 AM MST Per Nordlöw via Digitalmars-d- learn wrote: > On Tuesday, 25 December 2018 at 00:32:55 UTC, Paul Backus wrote: > > No, because equality comparison between classes lowers to > > `object.opEquals` [1], which takes both parameters as `Object`. > > This is a severe limitation. Are there any plans on fixing this > or do I have to wait for Andrei's proposed ProtoObject? ProtoObject _is_ the proposed fix, but if you want to use Object's opEquals in @safe code, you can always create a wrapper function that's marked @trusted and call that instead. - Jonathan M Davis
Re: Temporary @trusted scope
On Wednesday, December 19, 2018 1:19:42 AM MST rikki cattermole via Digitalmars-d-learn wrote: > On 19/12/2018 7:11 PM, Jonathan M Davis wrote: > > Really? I would have thought that that would be a pretty obvious > > optimization (especially if inlining is enabled). > > Assembly doesn't lie. I'm not saying that you're wrong, just expressing surprise. I've never checked to see what code actually got generated. But I do think that it's something that the compiler should be smart enough to do even if it isn't currently that smart, and the fact that it isn't is most defintely not a good thing. - Jonathan M Davis
Re: Checking if CTFE is used?
On Tuesday, December 18, 2018 9:20:11 AM MST berni via Digitalmars-d-learn wrote: > On Tuesday, 18 December 2018 at 14:32:29 UTC, Adam D. Ruppe wrote: > > CTFE is used if and only if it MUST be used by context. That's > > a runtime function, so no ctfe. > > > > Do something like: > > > > int[4] generate() { > > > >int[4] tmp; > >foreach(i; 0..4) tmp[i] = i; > >return tmp; > > > > } > > > > > > static immutable int[4] clue = generate(); > > Great, that worked. :-) My reasoning was, that CTFE is somewhat > greedy, that is, everything that can be evaluated at compile time > will be evaluated at compile time... > > Many thanks for your replies. :-) It's pretty much the opposite. CTFE is only ever done when the compiler needs the result at compile-time, and it's never done as an optimization, if nothing else because the compiler has no way of knowing whether the function is even CTFE-able until it actually tries. Having it attempt CTFE in a bunch of places and then give up (to then call the function at runtime instead) would likely have a very negative impact on compilation time - especially since CTFE isn't very efficient at the moment (though whenever the newCTFE that Stefan is working on finally lands, that should improve significantly). As things stand, you have complete control over when CTFE occurs, and it's usually pretty easy to figure out if it's happening or not. As long as you understand which things must be known at compile-time, it's straightforward. - Jonathan M Davis
Re: Temporary @trusted scope
On Tuesday, December 18, 2018 5:42:12 AM MST rikki cattermole via Digitalmars-d-learn wrote: > On 19/12/2018 1:34 AM, Per Nordlöw wrote: > > On Tuesday, 18 December 2018 at 10:42:51 UTC, Jonathan M Davis wrote: > >> Unfortunately, D does not currently have a way to do that. Only > >> functions can be marked with @trusted. However, the typical approach > >> to this problem is to use a lambda, which is more or less > >> syntactically the same except that it has some extra parens. e.g. > >> > >> () @trusted { doUnsafe(); }(); > > > > Is there a performance hit when using this? > > Yes except for ldc with -O3. > But it is a function not a delegate so it should be all nicely > prefetched and ready to go. So I wouldn't worry about it too much. Really? I would have thought that that would be a pretty obvious optimization (especially if inlining is enabled). I suppose that it doesn't entirely surprise me if dmd does a poor job of it, but I would have expected ldc to do better than that. I would think that such an improvement would be pretty low-hanging fruit for adding to dmd's optimizer though. If not, it sounds like further justification for adding a feature for this rather than having to use a lambda. Aside from that though, the lambda trick is simple enough that it wouldn't surprise me if Walter and Andrei's response to such a DIP would be to just use the lambda trick. - Jonathan M Davis
Re: Temporary @trusted scope
On Tuesday, December 18, 2018 3:14:50 AM MST Per Nordlöw via Digitalmars-d- learn wrote: > What's the preferred way of creating a temporary @trusted scope > without writing a separate function? > > Similar to Rust's > > unsafe { /* unsafe stuff here */ } Unfortunately, D does not currently have a way to do that. Only functions can be marked with @trusted. However, the typical approach to this problem is to use a lambda, which is more or less syntactically the same except that it has some extra parens. e.g. () @trusted { doUnsafe(); }(); or auto result = () @trusted { getUnsafe:() }(); So, it's less than ideal, but it gets us close, and unless the code is long enough that maybe it should be in its own function, it's better than declaring a nested function, let alone declaring an entirely separate function at module scope. - Jonathan M Davis
Re: Shared static this() not executed for unittest
On Sunday, December 16, 2018 12:53:43 PM MST Steven Schveighoffer via Digitalmars-d-learn wrote: > On 12/15/18 5:14 PM, Jonathan M Davis wrote: > > On Saturday, December 15, 2018 10:27:36 AM MST Neia Neutuladh via > > > > Digitalmars-d-learn wrote: > >> On Sat, 15 Dec 2018 17:19:05 +, Timoses wrote: > >>> Running `dub test` will output: > >>> Running ./unit-test-library writeln: unittest All unit tests have been > >>> run successfully. > >>> > >>> Why is the `shared static this()` not executed? > >> > >> Run `dub clean; dub test -v` and you'll see that main.d isn't compiled > >> into the test library. > >> > >> dub test substitutes its own main() function over yours. In order to do > >> this, it needs to not compile in your main() and to compile in its own. > >> dmd doesn't have an option to replace main(), so dub drops that entire > >> source file. > > > > Yeah. I hate how dub does this. I've been bitten by it on multiple > > occasions, and it's really easy to miss that this is happening. It > > probably would have been better if it required you to deal with main > > when the target type is an executable, resulting in a linker error when > > you didn't provide one. Instead, a number of us do stuff like > > This should be fixed, as DMD now supports just running the program with > --DRT-testmode=test-only and it will only run unit tests. That would be fantastic. - Jonathan M Davis
Re: Shared static this() not executed for unittest
On Saturday, December 15, 2018 10:27:36 AM MST Neia Neutuladh via Digitalmars-d-learn wrote: > On Sat, 15 Dec 2018 17:19:05 +, Timoses wrote: > > Running `dub test` will output: > > Running ./unit-test-library writeln: unittest All unit tests have been > > run successfully. > > > > Why is the `shared static this()` not executed? > > Run `dub clean; dub test -v` and you'll see that main.d isn't compiled > into the test library. > > dub test substitutes its own main() function over yours. In order to do > this, it needs to not compile in your main() and to compile in its own. > dmd doesn't have an option to replace main(), so dub drops that entire > source file. Yeah. I hate how dub does this. I've been bitten by it on multiple occasions, and it's really easy to miss that this is happening. It probably would have been better if it required you to deal with main when the target type is an executable, resulting in a linker error when you didn't provide one. Instead, a number of us do stuff like version(unittest) void main() {} void main() { ... } thinking that it's working, but whatever tests in the module with main simply don't get run, because that module isn't compiled in. Maybe dub should check the module with main to see if it contains any unittest blocks and print out warning if it does, but even if it did, it actually wouldn't have caught this case, because it involves a static constructor, not a unittest block. Anyway, the way that dub deals with this probably makes it so that the best thing to do in general is to make it so that the module with main is pretty much literally something like int main(string[] args) { import somemodulename; return realmain(args); } But of course, that just makes it so that you're less likely to accidentally do something like create a static this which won't be called with -unittest when you already know that that sort of thing is a problem with dub test. It doesn't help those folks who aren't aware of this behavior or who forget it. - Jonathan M Davis
Re: Bug in shifting
On Thursday, December 13, 2018 6:56:33 PM MST Steven Schveighoffer via Digitalmars-d-learn wrote: > On 12/13/18 7:16 PM, Michelle Long wrote: > > I've noticed the compiler is not throwing up errors and warnings like it > > used to: > > > > I thought D required breaks for cases? Seems it doesn't any longer! I'm > > only using -g -gf -d > > It doesn't require breaks for cases, it requires no fall-through on > cases. Again, an example would help describe what you mean. Well, to be more precise, it doesn't allow fallthrough when the case statement contains code. It will allow it when it doesn't. e.g. case 0: case 1: break; is perfectly legal. However, when the case statement contains code, then yeah, some form of control statement is required to exit the case statement, but that's a lot more than just break. continue, goto, return, etc. can all be used to exit a case statement. Any control statement that explicitly exits the case statement will work. And of course, goto case can be used for explicit fallthrough. - Jonathan M Davis
Re: OT (Was: Re: is(ElementType!(char[2]) == dchar - why?)
On Tuesday, December 11, 2018 2:11:49 PM MST H. S. Teoh via Digitalmars-d- learn wrote: > On Tue, Dec 11, 2018 at 09:02:41PM +, bauss via Digitalmars-d-learn wrote: > > On Tuesday, 11 December 2018 at 18:10:48 UTC, H. S. Teoh wrote: > [...] > > > > Autodecoding raises its ugly head again. :-/ > > [...] > > > Has it ever had anything else? > > LOL... well, we (or some of us) were deceived by its pretty tail for a > while, until we realized that it was just a façade, and Unicode really > didn't work the way we thought it did. Yeah. Auto-decoding came about, because Andrei misunderstood Unicode and thought that code points were complete characters (likely because the Unicode standard weirdly likes to refer to them as characters), and he didn't know about graphemes. At the time, many of us were just as clueless as he was (in many cases, more so), and auto-decoding made sense. You supposedly got full correctness by default and could work around it for increased performance when you needed to (and the standard library did that for you where it mattered, reducing how much you had to care). Walter knew better, but he wasn't involved enough with Phobos development to catch on until it was too late. It's only later when more folks involved came to a fuller understanding of Unicode that auto-decoding started to be panned. For instance, I very much doubt that you would find much from the D community talking about how horrible auto-decoding is back in 2010, whereas you probably could find plenty by 2015, and every time it comes up now, folks complain about it. Previously, folks would get annoyed about the restrictions, but the restrictions made sense with the understanding that code points were the actual characters, and you didn't want code to be chopping them up. But once it became more widely understood that code points were also potentially pieces of characters, you no longer had the same defense against the annoyances caused by how narrow strings are treated, and so it just became annoying. We went from newcomers getting annoyed, but those who understood the reasons behind auto-decoding being fine with it (because it supposedly made their code correct and prevented bugs) to almost everyone involved being annoyed about it. The newcomers who don't understand it still get annoyed by it, but instead of the ones who do understand it telling them about how it's helping keep Unicode handling correct, the folks who understand what's going now tell everyone how terrible auto-decoding is. So, the narrative that auto-decoding is terrible has now become the status quo, whereas before, it was actually considered to be a good thing by the D community at large, because it supposedly ensured Unicode correctness. It was still annoying, but that was because Unicode is annoying. Now, Unicode is still annoying, but auto-decoding is understood to make it even more so without actually helping. The one bright side out of all of this that makes it so that I don't think that auto-decoding is entirely bad is that it shoves the issue in everyone's faces so that everyone is forced to learn at least the basics about Unicode, whereas if we didn't have it, many folks would likely just treat char as a complete character and merrily write code that can't handle Unicode, since that's what usually happens in most programs in most languages (some languages do use the equivalent of wchar for their char, but most code still treats their char type as if it were a complete character). The fact that we have char, wchar, and dchar _does_ help raise the issue on its own, but auto-decoding makes it very hard to ignore. Now, that doesn't mean that I think that we should have auto-decoding (ideally, we'd figure out how to remove it), but the issues that it's caused have resulted in a lot of developers becoming much more knowledgeable about Unicode and therefore more likely to write code that handles Unicode correctly. - Jonathan M Davis
Re: Working with ranges
On Friday, December 7, 2018 8:46:11 PM MST Adam D. Ruppe via Digitalmars-d- learn wrote: > On Saturday, 8 December 2018 at 03:37:56 UTC, Murilo wrote: > > Hi guys, I have created an array of strings with "string[12] ps > > string[12] isn't a range, but string[] is. > > Try passing `ps[]` to the function instead of plain `ps` and see > what happens. Specifically, the problem is that static arrays have a fixed length, which means that you can't pop elements off as is required for ranges. Dynamic arrays on the other hand are ranges (at least as long as you import std.range.primitives to get the range functions for dynamic arrays). Slicing a static array gives you a dynamic array which is a slice of the static array. So, mutating the elements of the dynamic array will mutate the elements of the static array, but the dynamic array can have elements popped off as is required for ranges, whereas the static array can't. - Jonathan M Davis
Re: Writing Program Without main Function
On Friday, December 7, 2018 2:42:33 PM MST Samir via Digitalmars-d-learn wrote: > Ok. Upon further investigation, I think I see what is going on. > Most of the repos I am skimming are for this year's Advent of > Code. They structure their repo with an `app.d` file which does > contain a `main` function but this program is structured such > that it imports the files I was looking at earlier (which do not > have a `main` function). > > Looks like I have to get smarter on how modules, mixins and > imports work. There's one main per program, not per module. Where main lives depends on how the program was written, but dub encourages putting it in app.d, because that's what it generates when you create a new dub project. imports then provide access to other modules so that the code doing the importing can use it. You can think of it like the module with main being the start of the import tree, though it's a bit more complicated than that in practice, since modules can be compiled separately, and main only has to be there when the program is finally linked. But in concept, you have main and the module its in importing other modules, which then import other modules, etc. until you get all of the code in the program. - Jonathan M Davis
Re: Writing Program Without main Function
On Friday, December 7, 2018 2:02:59 PM MST Samir via Digitalmars-d-learn wrote: > Is it possible to write and execute a D program without a main > function? > > Most of my programs will start with some `import` statements, > followed by any functions and then ending with the `main` > function (e.g. `void main() {`). > > As I am just a beginner to programming and still new to D, I have > been browsing some repositories that people have posted here to > learn more about the language and how more experienced > programmers write their code. In many of these examples, they > start with the `module` statement followed by their `import` > statements and then will have sections defining various classes, > structs, unit tests and other bits but I never see a `main` > function. > > How do you compile and execute these programs? The short answer is that every program must have a main function. The long answer: main is the entry point into the program. You can't do much without it, and the linker will require that it exists. static constructors do get run before main, and static destructors get run after it, so it is possible to run code before and after main, but they're only intended for more complex initialization and destruction of module-level and static variables. Really, when it comes down to it, main _is_ your program, and there must be a main function one way or another. That's true of pretty much any programming language. Some may present main in a different way, but ultimately, every programming language has some form of main, because every program needs an entry point. dmd provides the -main flag which will insert an empty main, so you could use that, but it's really only of any use for unit testing (since in D, unittest blocks are run before main). For an actual program, you basically don't have anything without main. Essentially what you get in D is 1. Run static constructors. 2. If -unittest was used, run the unittest blocks (though since that's only intended for testing, it really shouldn't be in a production program). 3. Run main. 4. Run static destructors. And for simpler programs, you basically have 1. Run main. None of your stray functions or classes are going to be used just because you declared them. It's main that decides what's going to be run, even if it's just to call another function. All of those other functions and classes are just a way to organize your program, make pieces reusable, etc. Ultimately, the main function is your program, so it really doesn't make sense to try to not have one. The closest thing that exists to a program with no main is a library, and libraries are just collections of functions and user-defined types which are packaged together so that programs can use them. They aren't programs on their own, just pieces of reusable code. Ultimately, you need an actual program with a main to use them. When you see code snippets that don't use main, it's because they're usually just that - code snippets. They're showing a piece of code, not an entire program. It's just assumed that anyone who wants to actually run them is going to deal with declaring main themselves, because everyone knows that you need a main function. As such, including main is often just extraneous information. - Jonathan M Davis
Re: int[] as constructor
On Tuesday, December 4, 2018 3:17:04 PM MST jmh530 via Digitalmars-d-learn wrote: > I've noticed that I can use int like a constructor, as in: > int x = int(1); > but I can't do the same thing with slices > int[] y = int[]([1, 2]); > > Is there something I'm missing here or is this a potential > enhancement? It can make some types of generic code a little more > annoying. Using parens with dynamic arrays already has a different meaning. It's how you provide the size of the dynamic array. e.g. auto x = int[](12); or auto x = int[][](3, 4); In the first level, you can put the number in between the brackets instead - e.g. auto x = int[12]; but that falls apart at deeper levels, because the number in between the brackets would then mean a static array (making it so that you have a dynamic array of a static array). So, in the general case, parens are how you provide a dynamic array's length. This was true long before it became possible to use parens for construction with built-in types like you do with user-defined types. - Jonathan M Davis
Re: .dup vs operation on all elements
On Monday, December 3, 2018 1:07:24 PM MST Goksan via Digitalmars-d-learn wrote: > Are there any differences between these 2 methods of copying > elements? > > double[] array = [ 1, 20, 2, 30, 7, 11 ]; > > // Non dup > double[6] bracket_syntax_dup = array; > bracket_syntax_dup[] = array; > bracket_syntax_dup[0] = 50; > > // Dup > double[6] normal_dup = array.dup; > normal_dup[0] = 100; > > OUTPUT: (array, bracket_syntax_dup and normal_dup respectively): > [1, 20, 2, 30, 7, 11] > [50, 20, 2, 30, 7, 11] > [100, 20, 2, 30, 7, 11] dup allocates a new dynamic array and copies the elements of the existing dynamic array to the new one. Calling dup in order to assign to a static array is just needlessly allocating a dynamic array. The contents of the array are going to be copied to the static array regardless, but instead of just copying the elements, if you use dup, you're allocating a new dynamic array, copying the elements into that dynamic array, and then you're copying the elements into the static array. There's no point. You use dup when you want to copy the elements of a dynamic array instead of simply slicing it. Slicing gives you a new dynamic array that points to exactly the same elements. It's just copying the pointer and the length (meaning that mutating the elements of the new slice will affect the elements in the original array), whereas dup actually allocates a new block of memory for the new dynamic array to be a slice of (copying the elements over in the process), so mutating the elements in the new dynamic array then won't affect the elements in the original. Regardless, when you create a static array, it's not a slice of anything (since its elements sit directly on the stack), and when assign to it, you're simply copying the elements over. - Jonathan M Davis
Re: gcc 9 vs. dmd?
On Friday, November 30, 2018 2:43:41 AM MST welkam via Digitalmars-d-learn wrote: > On Friday, 30 November 2018 at 04:47:26 UTC, Andrew Pennebaker > > wrote: > > gcc is currently required for dmd on FreeBSD, as dmd links to > > libstdc++. > > Parts of dmd are still written in C++ but most of it was > converted recently. More on that here: > "DMD backend now in D" > https://forum.dlang.org/thread/psaekt$tah$1...@digitalmars.com That and the C/C++ compiler could be clang rather than gcc. Even without the backend being ported to D, there shouldn't be an actual dependency on gcc specifically (especially on FreeBSD where you may not even have gcc installed). But if I understand correctly, dmd has always used the C compiler to link on *nix systems rather than using the linker directly. I don't know why it does, but linking via the C compiler is a completely different issue from integrating with it. Regardless, as to the OP's question about gcc integration, that really doesn't have much to do with dmd. That's a big step forward for gdc, but dmd is the reference compiler. It's where everything is implemented. gdc and ldc are then alternate compilers that use the same front-end. but they're separate projects, and there's really no benefit to us at this point to removing dmd in favor of either of the other two. With dmd, we're in full control of the code and the release cycle, which is not true with llvm or gcc. Honestly, as great as it is for gdc to end up in the official gcc release, in practice, I expect that it's going to be a recipe for a portion of the community using an outdated version of the language (especially when coupled with stuff like LTS releases for Linux distros). That's already been a problem with gdc even without it being in the official gcc release due to how long it's taken them to catch up after the front-end was converted to D. Also, dmd's backend is the backend that Walter wrote and has used for decades - and it's part of dmc, which he still sells. So, I don't think that he's going to be in hurry to drop it. And if he were, I honestly expect that ldc would have become the reference compiler a while ago, not gdc. But dmd continues to be the reference compiler, and while improving its backend is not the focus, Walter still does work on it (and part of the reason that he's converted it to D is so that he can more easily improve it). Historically, Walter has wanted to stay away from gcc and clang code (or the code of any other compiler that isn't his), because in the past, he's found that being able to say that he's never read the source code has been a good defense against any kind of accusation of code stealing (which definitely matters when he's selling a C++ compiler). So, all the signs are that we're going to continue to have the choice of dmd, ldc, and gdc, and none of them are going anywhere. - Jonathan M Davis
Re: version(StdDoc)
On Saturday, November 24, 2018 10:41:56 PM MST H. S. Teoh via Digitalmars-d- learn wrote: > On Sat, Nov 24, 2018 at 05:48:16PM +, Stanislav Blinov via Digitalmars-d-learn wrote: > > On Saturday, 24 November 2018 at 17:43:35 UTC, Jonathan M Davis wrote: > > > I'm still inclined to think though that it should be legal to just > > > use version directly in the member list. > > > > Yup. UDAs did get in there eventually, and version should too. > > I think this would be a trivial DIP, by making it such that a version > block inside an enum would lower to the above code. Of course, it could > be taken further: the above trick doesn't quite handle this case: > > enum E { > a, > version(Windows) { > b, c > } > version(Posix) { > d > } > } > > But this looks like such an antipattern that it probably should be > written differently anyway, or just generated via a string mixin. It's something that comes up fairly frequently actually when dealing with system APIs. For instance, if you want your socket API to provide the full functionality of the underlying C API, then you're going to have to provide not only differing enum values for things like socket options or socket family, but you're actually going to have to provide different enum members in some cases. So, sure, if you're writing something that's purely D and can be properly platform-agnostic, then having different enum members for different platforms would be bad, but once C APIs get involved, I definitely would not consider it to be an anti-pattern. At that point, it has a tendency to become a necessity, and I've had several occasions where being able to version enum members would have made the code shorter. It also would have eliminated the need for version(D_Ddoc) (or the druntime or Phobos equivalents). - Jonathan M Davis
Re: version(StdDoc)
On Saturday, November 24, 2018 9:28:47 AM MST Stanislav Blinov via Digitalmars-d-learn wrote: > On Saturday, 24 November 2018 at 07:00:31 UTC, Jonathan M Davis > > wrote: > > [not legal] > > > > enum Foo > > { > > > > a, > > b, > > version(linux) c = 42, > > else version(Windows) c = 54, > > > > } > > > > You're forced to version the entire enum. > > Not in this case, no: > > enum Foo > { > a, > b, > c = { > version(linux) return 42; > else version(Windows) return 54; > } () > } > > /pedantry LOL. That's an interesting trick. It's ugly and hacky, but it does work around the problem. I'm still inclined to think though that it should be legal to just use version directly in the member list. - Jonathan M Davis
Re: version(StdDoc)
On Friday, November 23, 2018 11:22:24 PM MST Neia Neutuladh via Digitalmars- d-learn wrote: > On Fri, 23 Nov 2018 21:43:01 -0700, Jonathan M Davis wrote: > > A solution like that might work reasonably well, but you still > > have the problem of what to do when a symbol is documented in multiple > > version blocks, and having almost all the documentation in one version > > block and a few pieces of it in other version blocks would risk getting > > confusing and messy. > > Keeping symbol names and function arguments consistent between them is > also an issue; it's not just the documentation. The normal solution is to > put the version blocks inside the relevant symbols -- sometimes type > aliases inside version blocks and consistent code outside, sometimes > functions where the entire body is a set of version blocks. When you're versioning the implementation, it's trivial to just version the function internals. Where version(D_Ddoc) becomes critical is with stuff like structs or enums where the members actually differ across systems. And while it's generally better to try to avoid such situations, there are definitely situations where there isn't much choice. Fortunately, in the vast majority of situations, versioning across systems isn't required at all, and in most of the situations where it is, its only the implementation that needs to differ, but that's not true in all cases. I do wish though that it were legal to use version blocks in more situations than is currently the case. For instance, enum Foo { a, b, version(linux) l, else version(Windows) w, } is not legal, nor is enum Foo { a, b, version(linux) c = 42, else version(Windows) c = 54, } You're forced to version the entire enum. Fortunately, structs and classes, do not have that restriction, so having to version an entire struct or class at once is usually only required when the type needs to be declared on some systems but not others (as is the case with WindowsTimeZone), and such situations are rare. - Jonathan M Davis
Re: D is supposed to compile fast.
On Friday, November 23, 2018 11:13:24 AM MST H. S. Teoh via Digitalmars-d- learn wrote: > All in all, though, the fact that we're complaining about extra seconds > in compilation times still does show just how fast D compilation can be. > In the old days, compiling large C++ codebases usually means 30 mins to > 2 hours, and a few extra seconds won't even be noticed. I haven't > checked C++ compile times recently, though -- things may have improved > since I last seriously used C++. When I was a student, I worked for a while at a company that had a large C++ code base that took over 3 hours to compile from scratch (incremental builds were an absolute must). I ended up working somewhere else for a while and then coming back again, and in the interim, they had begun redoing the program in Java. The build process then took about 10 minutes, and folks were complaining about it taking too long. After having been away for a while, my perspective was that it was a _huge_ improvement, but since they'd been working with it for a while, the 10 minutes was annoying. So, a lot of it comes down to perspective. D is often a _huge_ improvement when you first switch to it, but depending on what your code does, over time, it can go from under a second to a few seconds in compilation time, and for some folks that becomes maddening in spite of the fact that the overall build times are a huge improvement over what they would have had in another language - and usually, the features that slow down the build the most are ones that don't even exist in other languages (or if they do, are far less powerful). That being said, if we can reasonably improve the compiler and standard library such that D code in general builds faster with all of the CTFE and templates, we definitely should. - Jonathan M Davis
Re: version(StdDoc)
On Friday, November 23, 2018 7:55:04 PM MST H. S. Teoh via Digitalmars-d- learn wrote: > Adam does have a very good point about showing all alternatives to docs, > though. Arguably, that's what ddoc *should* do. If the programmer > wrote a ddoc comment in the code, it probably should be processed as > part of doc generation, regardless of whether that code sits in some > deeply-nested version blocks that ends up not being compiled. Binding > ddoc generation to the compile process seems not such a good idea in > retrospect. Honestly, I would argue that if you have multiple versions of the documentation, then there's a serious problem. The documentation shouldn't be platform-dependent even if the symbols are. Even if the documentation needs some extra notes for a specific platform, it should all be in one documentation block that anyone using the symbol can read. Providing different documentation for different platforms just leads to folks not understanding how the symbol differs across platforms, leading to code that is even more platform-dependent when it really should be as platform independent as possible. The only situation I can think of at the moment where anything along the lines of combining documentation across platforms makes sense would be if there is a nested symbol that exists on only one platform (e.g. a member function of a struct or a member of an enum). In that case, one platform would have the main documentation, and then system-specific symbols would be documented in those version blocks - but only those symbols. A solution like that might work reasonably well, but you still have the problem of what to do when a symbol is documented in multiple version blocks, and having almost all the documentation in one version block and a few pieces of it in other version blocks would risk getting confusing and messy. As such, I'm not sure that the fact that ddoc forces you to have a separate set of declarations just for the documentation is really a bad thing. It puts all of the documentation in one place. The bigger problem IMHO is how -D affects the build. Both it and -unittest have the fundamental problem that because they create their own version identifiers, they really shouldn't be part of the normal build, and yet the way that they're set up to be used, it's as if they're expected to be part of the normal build - with -D just causing the compiler to generate the documentation in addition to the binary, and -unittest making the unit tests run before main rather than replacing main. At this point, I really wish that at minimum, -D were not set up to be part of the normal build process so that version(D_Ddoc) would not affect it. The same with -unittest. Ideally, it really would have replaced main rather than putting the unit tests before it, with it providing main if one wasn't there. That still doesn't solve all of the problems when using version(unittest), but I doubt that much of anyone really wants to be running unit tests as part of their application, and having such flags clearly designed to create special builds rather than being designed such that they could be used with the normal build would have fixed certain classes of problems. As for the issue of versioning the documentation, I don't really see a clean one. Having the documentation build affected by version and static if and the like causes some problems, but having it ignore them would likely cause other problems. Regardless, I suspect that having the version identifiers and static ifs be ignored almost requires a separate tool from the compiler (such as Adam's documentation generator or ddox), because it's pretty clear that ddoc was set up to generate the documentation for symbols as the compiler compiles them, whereas a tool that ignored version identifiers and static ifs would be processing the file quite differently. - Jonathan M Davis
Re: version(StdDoc)
On Friday, November 23, 2018 2:47:51 PM MST Tony via Digitalmars-d-learn wrote: > In std.compiler there is this code: > > /// Which vendor produced this compiler. > version(StdDdoc) Vendor vendor; > else version(DigitalMars) Vendor vendor = Vendor.digitalMars; > else version(GNU) Vendor vendor = Vendor.gnu; > else version(LDC) Vendor vendor = Vendor.llvm; > else version(D_NET) Vendor vendor = Vendor.dotNET; > else version(SDC) Vendor vendor = Vendor.sdc; > else Vendor vendor = Vendor.unknown; > > What is the situation in which the identifier StdDoc is set? It's a Phobos-only replacement for the D_Ddoc version identifier and is defined as part of the Phobos build. As the others have been complaining about in this thread, ddoc is set up so that it takes whatever version is currently being compiled. So, version(D_Ddoc) is the standard way to provide documentation that is agnostic of the platform in the cases where a documented symbol doesn't exist on all platforms, or its definition differs such that it needs separate declarations - e.g. if the values of members in an enum differ across systems, then you're forced to provide completely separate enum declarations for the entire enum. If you have separate declarations on different platforms, then in general there are only three choices 1. Duplicate the documentation. 2. Set it up so that your documentation can only be built on one platform. 3. Use version(D_Ddoc) to provide a separate declaration just for the documentation. There are some cases where you can put the documentation outside the version block and have it work - e.g. /// my documentation version(linux) int foo(string bar) { ... } else version(Windows) int foo(string bar) { ... } else ... but that only works when you only need to document the top-level symbol (such as with a function). It does not work with anything that needs to have symbols inside it documented (such as with a struct, class, or enum). Fortunately, most code does need to be versioned like this (especially if you're trying to write platform-independent code like we try to do with Phobos), and often, when you do need to version stuff, it's inside implementations, but sometimes it does affect the top level. std.file has this problem in a few places as does std.datetime with WindowsTimeZone (since it only exists on Windows). The solution the language provides is to use version(D_Ddoc) to version such documentation. And that's what Phobos used to do. The problem is that once you start using version(D_Ddoc), you _must_ have a separate documentation build. You can't build your documentation as part of your normal build, because you'd be getting the version(D_Ddoc) stubs instead of the correct implementation for your platform (or instead of nothing at all if that platform isn't supposed to have that particular symbol). Phobos already had a separate documentation build because of how it generates the documentation for the website, but many people's projects do not. Most projects don't ever need to use version(D_Ddoc), because they don't have symbols that are platform-dependent, and so before Phobos started using it, they could compile their documentation as part of their normal build just fine, because version(D_Ddoc) wasn't in their code anywhere. But as soon as Phobos started using it, their code broke. If they had had a separate documentation build, then they wouldn't have had any problems, but as it was, their code was broken. So, for better or worse, rather than saying that it was just bad practice to do the documentation build as part of your normal build (and I would strongly argue that building the documentation as part of the normal build is bad practice given how doing so defines a new version identifier that can affect the build), it was decided that Phobos would stop using version(D_Ddoc) as the language intended and instead use its own custom, version identifier for the documentation - which is why we now have version(StdDoc) in Phobos and version(CoreDdoc) in druntime. With this change, anyone building with the -D flag as part of their normal build doesn't end up with version(D_Ddoc) screwing up their code because of druntime or Phobos. Some other project they depend on could screw it up, and if they ever use version(D_Ddoc) in their code, they'll have trouble again, but Phobos and druntime aren't going to mess them up in that regard. And while version(D_Ddoc) is the standard solution, because of this general problem with folks using -D with their normal build, it's arguably best practice at this point to create your own version identifier for your own documentation for any library that you release that needs to version its documentation. Otherwise, anyone using your library will have the same problems that resulted in Phobos switching from version(D_Ddoc) to version(StdDdoc) - which if anything shows that things
Re: Why does nobody seem to think that `null` is a serious problem in D?
On Wednesday, November 21, 2018 3:24:06 PM MST Johan Engelen via Digitalmars-d-learn wrote: > On Wednesday, 21 November 2018 at 07:47:14 UTC, Jonathan M Davis > > wrote: > > IMHO, requiring something in the spec like "it must segfault > > when dereferencing null" as has been suggested before is > > probably not a good idea is really getting too specific > > (especially considering that some folks have argued that not > > all architectures segfault like x86 does), but ultimately, the > > question needs to be discussed with Walter. I did briefly > > discuss it with him at this last dconf, but I don't recall > > exactly what he had to say about the ldc optimization stuff. I > > _think_ that he was hoping that there was a way to tell the > > optimizer to just not do that kind of optimization, but I don't > > remember for sure. > > The issue is not specific to LDC at all. DMD also does > optimizations that assume that dereferencing [*] null is UB. The > example I gave is dead-code-elimination of a dead read of a > member variable inside a class method, which can only be done > either if the spec says that`a.foo()` is UB when `a` is null, or > if `this.a` is UB when `this` is null. > > [*] I notice you also use "dereference" for an execution machine > [**] reading from a memory address, instead of the language doing > a dereference (which may not necessarily mean a read from memory). > [**] intentional weird name for the CPU? Yes. We also have D code > running as webassembly... Skipping a dereference of null shouldn't be a problem as far as memory safety goes. The issue is if the compiler decides that UB allows it do to absolutely anything, and it rearranges the code in such a way that invalid memory is accessed. That cannot be allowed in @safe code in any D compiler. The code doesn't need to actually segfault, but it absolutely cannot access invalid memory even when optimized. Whether dmd's dead code elimination algorithm is able to make @safe code unsafe, I don't know. I'm not familiar with dmd's internals, and in general, while I have a basic understanding of the stuff at the various levels of a compiler, once the discussion gets to stuff like machine instructions and how the optimizer works, my understanding definitely isn't deep. After we discussed this issue with regards to ldc at dconf, I brought it up with Walter, and he didn't seem to think that dmd had such a problem, but I didn't think to raise that particular possibility either. It wouldn't surprise me if dmd also had issues in its optimizer that made @safe not @safe, and it wouldn't surprise me if it didn't. It's the sort of area where I'd expect that ldc's more aggressive optimizations to be much more likely to run into trouble, and it's more likely to do things that Walter isn't familiar with, but that doesn't mean that Walter didn't miss anything with dmd either. After all, he does seem to like the idea of allowing the optimizer to assume that assertions are true, and as far as I can tell based on discussions on that topic, he doesn't seem to have understood (or maybe just didn't agree) that if we did that, the optimizer can't be allowed to make that assumption if there's any possibility of the code not being memory safe if the assumption is wrong (at least not without violating the guarantees that @safe is supposed to provide). Since if the assumption turns out to be wrong (which is quite possible, even if it's not likely in well-tested code), then @safe would then violate memory safety. As I understand it, by definition, @safe code is supposed to not have undefined behavior in it, and certainly, if any compiler's optimizer takes undefined behavior as meaning that it can do whatever it wants at that point with no restrictions (which is what I gathered from our discussion at dconf), then I don't see how any D compiler's optimizer can be allowed to think that anything is UB in @safe code. That may be why Walter was updating various parts of the spec a while back to talk about compiler-defined as opposed to undefined, since there are certainly areas where the compiler can have leeway with what it does, but there are places (at least in @safe code), where there must be restrictions on what it can assume and do even when the implementation is given leeway, or @safe's memory safety guarantees won't actually be properly guaranteed. In any case, clearly this needs to be sorted out with Walter, and the D spec needs to be updated in whatever manner best fixes the problem. Null pointers / references need to be guaranteed to be @safe in @safe code. Whether that's going to require that the compiler insert additional null checks in at least some places, I don't know. I simply don't know enough about how things work with stuff like the optimizers, but it wouldn't surprise me if in at least some cases, the compiler is ultimately going to be forced to insert null checks. Certainly, at minimum, I think that it's quite clear that if a platform doesn't
Re: Why does nobody seem to think that `null` is a serious problem in D?
On Tuesday, November 20, 2018 11:04:08 AM MST Johan Engelen via Digitalmars- d-learn wrote: > On Tuesday, 20 November 2018 at 03:38:14 UTC, Jonathan M Davis > > wrote: > > For @safe to function properly, dereferencing null _must_ be > > guaranteed to be memory safe, and for dmd it is, since it will > > always segfault. Unfortunately, as understand it, it is > > currently possible with ldc's optimizer to run into trouble, > > since it'll do things like see that something must be null and > > therefore assume that it must never be dereferenced, since it > > would clearly be wrong to dereference it. And then when the > > code hits a point where it _does_ try to dereference it, you > > get undefined behavior. It's something that needs to be fixed > > in ldc, but based on discussions I had with Johan at dconf this > > year about the issue, I suspect that the spec is going to have > > to be updated to be very clear on how dereferencing null has to > > be handled before the ldc guys do anything about it. As long as > > the optimizer doesn't get involved everything is fine, but as > > great as optimizers can be at making code faster, they aren't > > really written with stuff like @safe in mind. > > One big problem is the way people talk and write about this > issue. There is a difference between "dereferencing" in the > language, and reading from a memory address by the CPU. > Confusing language semantics with what the CPU is doing happens > often in the D community and is not helping these debates. > > D is proclaiming that dereferencing `null` must segfault but that > is not implemented by any of the compilers. It would require > inserting null checks upon every dereference. (This may not be as > slow as you may think, but it would probably not make code run > faster.) > > An example: > ``` > class A { > int i; > final void foo() { > import std.stdio; writeln(__LINE__); > // i = 5; > } > } > > void main() { > A a; > a.foo(); > } > ``` > > In this case, the actual null dereference happens on the last > line of main. The program runs fine however since dlang 2.077. > Now when `foo` is modified such that it writes to member field > `i`, the program does segfault (writes to address 0). > D does not make dereferencing on class objects explicit, which > makes it harder to see where the dereference is happening. Yeah. It's one of those areas where the spec will need to be clear. Like C++, D doesn't actually dereference unless it needs to. And IMHO, that's fine. The core issue is that operations that aren't memory safe can't be allowed to happen in @safe code, and the spec needs to be defined in such a way that requires that that be true, though not necessarily by being super specific about every detail about how a compiler is required to do it. > So, I think all compiler implementations are not spec compliant > on this point. > I think most people believe that compliance is too costly for the > kind of software one wants to write in D; the issue is similar to > array bounds checking that people explicitly disable or work > around. > For compliance we would need to change the compiler to emit null > checks on all @safe dereferences (the opposite direction was > chosen in 2.077). It'd be interesting to do the experiment. Ultimately here, the key thing is that it must be guaranteed that dereferencing null is @safe in @safe code (regardless of whether that involves * or . and regardless of how that is achieved). It must never read from or write to invalid memory. If it can, then dereferencing a null pointer or class reference is not memory safe, and since there's no way to know whether a pointer or class reference is null or not via the type system, dereferencing pointers and references in general would then be @system, and that simply can't be the case, or @safe is completely broken. Typically, that protection is done right now via segfaults, but we know that that's not always possible. For instance, if the object is large enough (larger than one page size IIRC), then attempting to dereference a null pointer won't necessarily segfault. It can actually end up accessing invalid memory if you try to access a member variable that's deep enough in the object. I know that in that particular case, Walter's answer to the problem is that such objects should be illegal in @safe code, but AFAIK, neither the compiler nor the spec have yet been updated to match that decision, which needs to be fixed. But regardless, in any and all cases where we determine that a segfault won't necessarily protect against accessing invalid memory when a null pointer or reference is dereferenced, then we need to do _something_ to guarantee that that code is @safe - which probably means adding additional null checks in most cases, though in the case of the overly large object, Walter has a different solution. IMHO, requiring something in the spec like "it must segfault when dereferencing null" as has been
Re: Why does nobody seem to think that `null` is a serious problem in D?
On Tuesday, November 20, 2018 8:38:40 AM MST Kagamin via Digitalmars-d-learn wrote: > On Monday, 19 November 2018 at 21:23:31 UTC, Jordi Gutiérrez > > Hermoso wrote: > > When I was first playing with D, I managed to create a segfault > > by doing `SomeClass c;` and then trying do something with the > > object I thought I had default-created, by analogy with C++ > > syntax. > > D is more similar to Java here and works like languages with > reference types - Java, C#, Python, Ruby, JavaScript. Also AFAIK > in C++ objects are garbage-created by default, so you would have > a similar problem there. To diagnose crashes on linux you can run > your program under gdb. In C++, if the class is put directly on the stack, then you get a similar situation to D's structs, only instead of it being default-initialized, it's default-constructed. So, you don't normally get garbage when you just declare a variable of a class type (though you do with other types, and IIRC, if a class doesn't have a user-defined default constructor, and a member variable's type doesn't have a default constructor, then that member variable does end up being garbage). However, if you declare a pointer to a class (which is really more analagous to what you're doing when declaring a class reference in D), then it's most definitely garbage, and the behavior is usually _far_ worse than segfaulting. So, while I can see someone getting annoyed about a segfault, because they forgot to initialize a class reference in D, the end result is far, far safer than what C++ does. And in most cases, you catch the bug pretty fast, because pretty much the only way that you don't catch it is if that piece of code is never tested. So, while D's approach is by no means perfect, I don't think that there's really any question that as far as memory safety goes, it's far superior to C++. - Jonathan M Davis
Re: Why does nobody seem to think that `null` is a serious problem in D?
On Monday, November 19, 2018 5:30:00 PM MST Steven Schveighoffer via Digitalmars-d-learn wrote: > On 11/19/18 7:21 PM, Jordi Gutiérrez Hermoso wrote: > > On Monday, 19 November 2018 at 21:52:47 UTC, Steven Schveighoffer wrote: > >> A null pointer dereference is an immediate error, and it's also a safe > >> error. It does not cause corruption, and it is free (the MMU is doing > >> it for you). > > > > Is this always true for all arches that D can compile to? I remember > > back in the DOS days with no memory protection you really could read OS > > data around the beginning. > > It's true for all OSes that D supports, and for most modern operating > systems, that run in protected mode. > > It would NOT necessarily be true for kernel modules or an OS kernel, so > that is something to be concerned about. For @safe to function properly, dereferencing null _must_ be guaranteed to be memory safe, and for dmd it is, since it will always segfault. Unfortunately, as understand it, it is currently possible with ldc's optimizer to run into trouble, since it'll do things like see that something must be null and therefore assume that it must never be dereferenced, since it would clearly be wrong to dereference it. And then when the code hits a point where it _does_ try to dereference it, you get undefined behavior. It's something that needs to be fixed in ldc, but based on discussions I had with Johan at dconf this year about the issue, I suspect that the spec is going to have to be updated to be very clear on how dereferencing null has to be handled before the ldc guys do anything about it. As long as the optimizer doesn't get involved everything is fine, but as great as optimizers can be at making code faster, they aren't really written with stuff like @safe in mind. > >> Consistent segfaults are generally easy to figure out. > > > > I think I would still prefer a stack trace like other kinds of D errors. > > Is this too difficult? > > Yes and no. It's good to remember that this is a HARDWARE generated > exception, and each OS handles it differently. It's also important to > remember that a segmentation fault is NOT necessarily the result of a > simple error like forgetting to initialize a variable. It could be a > serious memory corruption error. Generating stack traces can be > dangerous in this kind of state. > > As I said, on Linux you can enable a "hack" that generates an error for > a null dereference. On Windows, I believe that it already generates an > exception without any modification. > > On other OSes you may be out of luck until someone figures out a nice > clever hack for it. > > And if it's repeatable, you can always run in a debugger to see where > the error is occurring. Also, if your OS supports core dumps, and you have them turned on, then it's trivial to get a stack trace - as well as a lot more of the program state. - Jonathan M Davis
Re: opDispatch doesn't play nice with inheritance
On Saturday, November 17, 2018 11:09:51 PM MST Carl Sturtivant via Digitalmars-d-learn wrote: > On Thursday, 15 November 2018 at 19:01:45 UTC, Ali Çehreli wrote: > > On 11/15/2018 09:14 AM, Carl Sturtivant wrote: > > > opDispatch is special in that it allows for functions to be > > > > added to a > > > > > class or struct when undefined overtly but used elsewhere but > > > > it seems > > > > > those functions sadly are final. > > > > > > Can anything useful be done to remedy the situation? > > > > For the compiler to be able to make all opDispatch > > instantiations virtual, it would have to first see all calls > > that generate opDispatch instantiations. (Impossible in the > > presence of separate compilation.) > > > > Only then the compiler would know how large the vtbl of the > > base class should be and what member functions of the derived > > class are overrides of those virtual functions. > > I suppose it's such administrative difficulties that led to D > defining anything that might conceivably be overridden to be > virtual, whether or not actually overridden. The issue with templated functions is that you don't have the full list of instantiations when the base class is compiled, whereas as I understand it, the issue with virtual-by-default is more of an issue of choosing code correctness by default over efficiency by default. You can get some fun, subtle bugs in C++ when you call non-virtual functions in circumstances where they were overridden and used as if they were virtual. So, by making all public and protected class member functions virtual by default and not allowing non-virtual functions to be overridden, it prevents a whole class of bugs. It _does_ have some performance downsides in that it easily leads to functions being virtual when they don't need to be, which can be gotten around with some extra effort, but it's effectively favoring correctness by default over efficiency. And for a lot of programs, it's a great tradeoff, especially when the whole point of classes in D is to use inheritance and polymorphism, and the cases where you don't need it, you use a struct. For the rest, final can be used to devirtualize a function as long as it's not overriding a function. To avoid bugs in the same way that we currently do without having virtual be the default, we probably would have had to make it illegal to override any class functions unless they were explicitly virtual, which would have created a different set of problems. And whether that would be better or worse is a matter of debate. In the end, it's a matter of tradeoffs, and which is better is likely to depend on how your applications benefit from and use the feature. If most of your class functions are used polymorphically, then having to mark them as virtual or having to put virtual: at the top of your class would get really annoying, whereas if you typically have only a few virtual functions and then lots of non-virtual property functions (like the AAA guys apparently like to do), then having to mark things with final to devirtualize them is very annoying. There's no pleasing everyone. Either way, allowing overriding non-virtual functions like C++ does would just be begging for bugs. - Jonathan M Davis
Re: Problem with opBinary
On Wednesday, November 14, 2018 2:54:27 AM MST realhet via Digitalmars-d- learn wrote: > Hi, > > Just a little weird thing I noticed and don't know why it is: > > I have a FilePath struct and I wanted to make it work with the > "~" operator and an additional string. > > So I've created a global funct: > >FilePath opBinary(string op:"~")(FilePath p1, string p2){ > return FilePath(p1, p2); >} > > The problem is that this funct is only callable with the > following code: > >auto vlcPath = programFilesPath.opBinary!"~"(`VideoLAN\VLC`); > > And it is not callable using the ~ operator directly. It says > unable to call with types FilePath and string > > When I rewrite the opBinary funct as a member of the FilePath > struct, everything is working fine. The problem is only happening > when opBinary is a global funct. (I'm using LDC Win64) > > Is it a bug or is there an explanation to this? In D, all overloaded operators must be member functions. - Jonathan M Davis
Re: Why is stdio ... stdio?
On Saturday, November 10, 2018 7:51:36 PM MST Adam D. Ruppe via Digitalmars- d-learn wrote: > On Saturday, 10 November 2018 at 23:29:12 UTC, Jonathan M Davis > > wrote: > > The fact that they got added to ddoc just further degrades it > > as a proper, macro-based markup language. > > The backticks were added to ddoc because they enabled something > that was *virtually impossible* in ddoc before - proper character > escaping. It actually originally had nothing to do with syntax > sugar nor even with presentation - just the constant repetition > of that myth has made it into a bit of reality. It may be that a feature was needed to do better character escaping, but backticks really don't fit in with ddoc as a whole, and they've only encouraged folks to try and add further markdown features to ddoc, which IMHO, is incredibly negative. On the whole, the worst features of ddoc are the ones that act least like macros. They're the ones that are most "magical" and the ones that generally have to be fought and worked around. Adding more markdown features just makes things worse. As such, I very much wish that we'd found a different way to fix the character escaping problem. Regardless, none of that has anything to do with what we do with syntax highlighting in the newsgroup's web interface. > On the forum though, characters are already escaped properly, so > there's no need here. Syntax highlighting for larger blocks is > something I'm meh on - I don't really care either way if we > wanted to do it. I don't really care what the web interface tries to highlight, but I don't want it doing anything that encourages people to start putting markdown in their messages, because I don't use the web interface, I don't want to have to see markdown in the middle of plain text messages any more than I want to see html. - Jonathan M Davis
Re: Why is stdio ... stdio?
On Saturday, November 10, 2018 6:53:14 AM MST Kagamin via Digitalmars-d- learn wrote: > On Friday, 9 November 2018 at 09:11:37 UTC, Jonathan M Davis > > wrote: > > No, I didn't. I just used underscores, which has been used with > > plain text for emphasis for decades. Supporting markdown, would > > involve stuff like backticks for code highlighting Backticks are not from ddoc. They're from markdown and only got added to ddoc later. The fact that they got added to ddoc just further degrades it as a proper, macro-based markup language. Regardless, if it isn't clear that something is code, just put it on its own line, just like folks have been doing in mailing lists and newsgroups for decades. - Jonathan M Davis
Re: Using decodeFront with a generalised input range
On Friday, November 9, 2018 5:22:27 AM MST Vinay Sajip via Digitalmars-d- learn wrote: > On Friday, 9 November 2018 at 11:24:42 UTC, Jonathan M Davis > > wrote: > > decode and decodeFront are for converting a UTF code unit to a > > Unicode code point. So, you're taking UTF-8 code unit (char), > > UTF-16 code unit (wchar), or a UTF-32 code unit (dchar) and > > decoding it. In the case of UTF-32, that's a no-op, since > > UTF-32 code units are already code points, but for UTF-8 and > > UTF-16, they're not the same at all. > > > > I would advise against doing much with decode or decodeFront > > without having a decent understanding of the basics of Unicode. > > I think I understand enough of the basics of Unicode, at least > for my application; my unfamiliarity is with the D language and > standard library, to which I am very new. > > There are applications where one needs to decode a stream of > bytes into Unicode text: perhaps it's just semantic quibbling > distinguishing between "a ubyte" and "a UTF-8 code unit", as > they're the same at the level of bits and bytes (as I understand > it - please tell me if you think otherwise). If I open a file > using mode "rb", I get a sequence of bytes, which may contain > structured binary data, parts of which are to be interpreted as > text encoded in UTF-8. Is there something in the D standard > library which enables incremental decoding of such (parts of) a > byte stream? Or does one have to resort to the `map!(x => > cast(char) x)` method for this? In principle, a char is assumed to be a UTF-8 code unit, though it's certainly possible for code to manage to end up with a char that's not a valid UTF-8 code unit. So, char is specifically a character type, whereas byte and ubyte are 8 bit integer types which can contain arbitrary data. D purposefully has char, wchar, and dchar as separate types from byte, ubyte, short, ushort, etc. in order to distinguish between character types and integer types, and in general, the D standard library does not treat byte or ubyte as having anything to do with characters. decode and decodeFront operate on ranges of characters, not ranges of arbitrary integer types. So, if you have a range of byte or ubyte which contains UTF-8 code units, and you want to use decode or decodeFront, then you will need to convert that range to a range of char. map would likely be the most straightforward way to do that. - Jonathan M Davis
Re: Using decodeFront with a generalised input range
On Friday, November 9, 2018 3:45:49 AM MST Vinay Sajip via Digitalmars-d- learn wrote: > On Friday, 9 November 2018 at 10:26:46 UTC, Dennis wrote: > > On Friday, 9 November 2018 at 09:47:32 UTC, Vinay Sajip wrote: > >> std.utf.decodeFront(Flag useReplacementDchar = > >> No.useReplacementDchar, S)(ref S str) if (isInputRange!S && > >> isSomeChar!(ElementType!S)) > > > > This is the overload you want, let's check if it matches: > > ref S str - your InputRange can be passed by reference, but you > > specified S = dchar. S here is the type of the inputRange, and > > it is not of type dchar. It's best not to specify S so the > > compiler will infer it, range types can be very complicated. > > Once we fix that, let's look at the rest: > > > > isInputRange!S - S is an inputRange > > isSomeChar!(ElementType!S) - ElementType!S is ubyte, but > > isSomeChar!ubyte is not true. > > > > The function wants characters, but you give bytes. A quick fix > > would be to do: > > ``` > > import std.algorithm: map; > > auto mapped = r.map!(x => cast(char) x); > > mapped.decodeFront!(No.useReplacementDchar)(); > > ``` > > > > But it may be better for somefn to accept an InputRange!(char) > > instead. > > > > Note that if you directly do: > > ``` > > r.map!(x => cast(char) > > x).decodeFront!(No.useReplacementDchar)(); > > ``` > > It still won't work, since it wants `ref S str` and r.map!(...) > > is a temporary that can't be passed by reference. > > > > As you can see, ensuring template constraints can be really > > difficult. The error messages give little help here, so you > > have to manually check whether the conditions of the overload > > you want hold. > > Thanks, that's helpful. My confusion seems due to my thinking > that a decoding operation converts (unsigned) bytes to chars, > which is not how the writers of std.utf seem to have thought of > it. As I see it, a ubyte 0x20 could be decoded to an ASCII char ' > ', and likewise to wchar or dchar. It doesn't (to me) make sense > to decode a char to a wchar or dchar. Anyway, you've shown me how > decodeFront can be used, so great! decode and decodeFront are for converting a UTF code unit to a Unicode code point. So, you're taking UTF-8 code unit (char), UTF-16 code unit (wchar), or a UTF-32 code unit (dchar) and decoding it. In the case of UTF-32, that's a no-op, since UTF-32 code units are already code points, but for UTF-8 and UTF-16, they're not the same at all. For UTF-8, a code point is encoded as 1 to 4 code units which are 8 bits in size (char). For UTF-16, a code point is encoded as 1 or 2 code units which are 16 bits in size (wchar), and for UTF-32, code points are encoded as code units which are 32-bits in size (dchar). The decoding is doing that conversion. None of this has anything to do with ASCII or any other encoding except insofar as ASCII happens to line up with Unicode. Code points are then 32-bit integer values (which D represents as dchar). They are often called Unicode characters, and can be represented graphically, but many of them represent bits of what you would actually consider to be a character (e.g. an accent could be a code point on its own), so in many cases, code points have to be combine to create what's called a grapheme or grapheme cluster (which unfortunately, means that can can have to worry about normalizing code points). std.uni provides code for worrying about that sort of thing. Ultimately, what gets rendered to the screen by with a font is as grapheme. In the simplest case, with an ASCII character, a single character is a single code unit, a single code point, and a single grapheme in all representations, but with more complex characters (e.g. a Hebrew character or a character with a couple of accents on it), it could be several code units, one or more code points, and a single grapheme. I would advise against doing much with decode or decodeFront without having a decent understanding of the basics of Unicode. > Supplementary question: is an operation like r.map!(x => > cast(char) x) effectively a run-time no-op and just to keep the > compiler happy, or does it actually result in code being > executed? I came across a similar issue with ranges recently > where the answer was to map immutable(byte) to byte in the same > way. That would depend on the optimization flags chosen and the exact code in question. In general, ldc is more likely to do a good job at optimizing such code than dmd, though dmd doesn't necessarily do a bad job. I don't know how good a job dmd does in this particular case. It depends on the code. In general, dmd compiles very quickly and as such is great for development, whereas ldc does a better job at generating fast executables. I would expect ldc to optimize such code properly. - Jonathan M Davis
Re: Why is stdio ... stdio?
On Friday, November 9, 2018 1:27:44 AM MST Kagamin via Digitalmars-d-learn wrote: > On Friday, 9 November 2018 at 06:42:37 UTC, Jonathan M Davis > > wrote: > > Honestly, having markdown in messages being typical would be > > _really_ annoying for those of us not using the web interface, > > because we'd see all of those backticks and the like as > > backticks, not as syntax highlighting. It would be like seeing > > html, albeit far less intrusive. I for one would much rather > > that things just stay as pure text and that we not be adding > > any features to the web interface that encourages adding _any_ > > kind of markup to messages. The web interface makes it easier > > for folks who don't want to use a newsgroup or mailing list to > > interact with the newsgroup, but it's still a newsgroup, and > > _many_ of us use it as such. > > You used markdown three times in your message. No, I didn't. I just used underscores, which has been used with plain text for emphasis for decades. Supporting markdown, would involve stuff like backticks for code highlighting, and special markup for urls - stuff that doesn't actually provide information to someone who's reading plain text but just gets in the way, whereas the underscores _do_ provide information to someone reading plain text. - Jonathan M Davis
Re: Why is stdio ... stdio?
On Thursday, November 8, 2018 7:25:45 PM MST Neia Neutuladh via Digitalmars- d-learn wrote: > It's not a forum. It's a newsgroup that happens to have a web interface. > Newsgroups are text-only. So bbcode is out, html is out, but interpreting > markdown might be reasonable. But nobody's done that work. Honestly, having markdown in messages being typical would be _really_ annoying for those of us not using the web interface, because we'd see all of those backticks and the like as backticks, not as syntax highlighting. It would be like seeing html, albeit far less intrusive. I for one would much rather that things just stay as pure text and that we not be adding any features to the web interface that encourages adding _any_ kind of markup to messages. The web interface makes it easier for folks who don't want to use a newsgroup or mailing list to interact with the newsgroup, but it's still a newsgroup, and _many_ of us use it as such. - Jonathan M Davis
Re: Exception slipping through the catch block?
On Thursday, November 8, 2018 2:34:38 PM MST H. S. Teoh via Digitalmars-d- learn wrote: > On Thu, Nov 08, 2018 at 01:28:47PM -0700, Jonathan M Davis via Digitalmars-d-learn wrote: > > On Thursday, November 8, 2018 10:55:45 AM MST Stanislav Blinov via > > > > Digitalmars-d-learn wrote: > > > On Thursday, 8 November 2018 at 16:13:55 UTC, Mike Parker wrote: > [...] > > > > > No, you should never catch Errors. They're separate for a > > > > reason. > > > > > > Never say never :) There are legitimate cases for catching an > > > Error or even a Throwable (for example, error propagation in a > > > multi-threaded environment). However, this is not one of such > > > cases. > > > > Yeah, but basically, the rule of thumb is never. Errors are fatal > > error conditions which are supposed to terminate the program, and > > programs should not be trying to recover from them. No one should be > > attempting to catch them unless they know what they're doing, which > > honestly, probably isn't going to be very many people for something > > like this. > > Recently I ran into a case where catching Throwable makes sense: I have > an Android application where the main code interfacing with the Android > OS is written in Java, but program logic is written in D, called via > JNI. Since the JVM obviously cannot handle D exceptions, any unhandled > D exception that makes it past the JNI boundary would cause the > application to crash. So what I did was to have the JNI interfacing > code (on the D side) catch *everything*, i.e., Throwable, marshall the > error message into a Java object, then send it via JNI back to the Java > code that then displays the error message before aborting the > application. Extremely valuable in debugging, since otherwise I'd have > to extract the stacktrace from the system logs, which is a pain. You ran into one of the rare cases where it makes sense catch an Error or a Throwable, and you're one of the few people who understands the situation well enough to deal with it properly. The vast majority of D programmers don't. Certainly, anyone who has to ask about the differences between Throwable, Error, and Exception doesn't. - Jonathan M Davis
Re: Exception slipping through the catch block?
On Thursday, November 8, 2018 10:55:45 AM MST Stanislav Blinov via Digitalmars-d-learn wrote: > On Thursday, 8 November 2018 at 16:13:55 UTC, Mike Parker wrote: > > On Thursday, 8 November 2018 at 15:50:38 UTC, helxi wrote: > >> Although it's pretty frustrating, isn't it? Now not only I > >> have to think about catching exceptions but also about Errors, > >> and have no guarantee that I have everything under control. > > > > No, you should never catch Errors. They're separate for a > > reason. > > Never say never :) There are legitimate cases for catching an > Error or even a Throwable (for example, error propagation in a > multi-threaded environment). However, this is not one of such > cases. Yeah, but basically, the rule of thumb is never. Errors are fatal error conditions which are supposed to terminate the program, and programs should not be trying to recover from them. No one should be attempting to catch them unless they know what they're doing, which honestly, probably isn't going to be very many people for something like this. Exceptions are for error conditions which are potentially recoverable. Program input or environmental state was bad (e.g. a missing file). They aren't necessarily indicative of bugs in the program, and the program can potentially recover from them and continue to function perfectly fine. Errors on the other hand, are used to indicate actual bugs in the program or fatal conditions with resources which cannot be recovered from (e.g. the GC running out of memory). They are intended simply to be informative and not to be caught. The stack is not necessarily properly unwound when they are thrown. Full exception handling code is not necessarily even in place when they are thrown, and they can be thrown from nothrow code. By definition, your program is in an invalid state when you catch an Error, and catching an Error to do much of anything is dangerous. > helxi, an AssertError means there's a problem with your code, it > needs to be dealt with by fixing the code, not swallowing the > Error. Specifically, AssertError means that either an assertion failed or something simulating an assertion failed (such as std.exception.assertThrown), so it's something in the code that quite specifically indicates that there's a bug in the code and that a condition that must be true for the code to be in a valid state was false. So, whatever it reported should be tracked down and fixed. In this particular case, it looks like a piece of code called dropBackOne on an empty range. - Jonathan M Davis
Re: Is this a bug? +goto
On Thursday, November 8, 2018 2:34:34 AM MST Michelle Long via Digitalmars- d-learn wrote: > Obviously, but that is not the case I mentioned. You can assume > that I know how scopes work. No need to assume everyone that > shows two cases that you have to bring up an unrelated case as a > potential cause unless it is relevant. > > Remember, I'm showing the starting case that has the bug and the > final case that doesn't... it is simply "mental dustmite" on the > code I have. > > You shouldn't assume everyone can't comprehend such trivialities. > > If a person cannot understand scope then I doubt they understand > goto's... and definitely not that adding braces should not change > the compiler behavior. > > What happens when you do that you just create noise that makes it > more difficult to have a proper discussion that gets at the whole > point of the conversation. > > You seem to default to assuming that the person you are talking > to has no clue about the problem at hand. You might not do it > intentionally but it is wrong to assume that because it almost > never helps. If you fully understood the situation, you wouldn't be asking whether your case was a compiler bug or not, and I don't know which parts you do and don't understand. So, I tried to be thorough in explaining the situation. And yes, by being thorough, I'm more likely to cover information that you already know and understand, but I'm also more likely to cover the information that you actually need. In order to avoid repeating anything you already understand and only tell you exactly what you need to know, I would have to somehow understand exactly which piece of the puzzle it is you're missing, and I don't. Honestly, that rarely seems to be easy to do, and for whatever reason, it seems to be even harder to do than normal when discussing this issue with you. It seems like most of the discussion of this issue between you and various folks has been people talking passed each other without really coming to an understanding, which always makes for a frustrating discussion. I'd like to help, but I don't know what else I can say. I've tried to explain how braces interact with goto and why, so you should be able to figure out whether you're dealing with a compiler bug or not. And if you are, unless you're dealing with one that someone else already has found independently and reported with a test case, somehow, you're going to need to reduce it enough to be able to create a bug report with an example if you want it fixed. A small example would be nice, but even a large example would be better than nothing. Either way, ultimately, without a reproducible test case, compiler bugs almost never get fixed. It just isn't practical for the compiler devs to track down bugs based on vague bug reports, even if they'd like to be helpful. - Jonathan M Davis
Re: is opOpAssign returning a value less than ideal ?
On Thursday, November 8, 2018 2:15:43 AM MST Codifies via Digitalmars-d-learn wrote: > On Thursday, 8 November 2018 at 06:01:57 UTC, Jonathan M Davis > > wrote: > > On Wednesday, November 7, 2018 10:45:07 PM MST Jonathan M Davis > > > > via Digitalmars-d-learn wrote: > >> [...] > > > > Rereading what you wrote, are you asking whether it's > > reasonable to return a value instead of a reference? > > Personally, I don't think that that's good design at all, but I > > also don't see any reason for the compiler to prevent it. > > > > Personally, I think that the default design should be to return > > by ref. Returning void is less than ideal but isn't necessarily > > bad, depending on the situation (especially if we're not > > talking about a general purpose library). However, I expect > > that returning non-void by value rather than by ref is rarely > > -if ever - going to be a good design choice. It's just going to > > be confusing and not particularly useful. > > > > - Jonathan M Davis > > NB its not returning a ref to the list, its returning the newly > created node when you use the operator you add a type to the > list, so it possibly wouldn't be that much use for chaining? The normal thing to do with any of the assignment operators is to return a reference to the object you're assigning to. Doing much of anything else other than returning void (and thus not allowing chaining) would be pretty abnormal. If it's appropriately documented, having an assignment operator return something else could certainly be made to work, but I expect that most programmers would consider it to be a backwards API. - Jonathan M Davis
Re: Is this a bug? +goto
On Wednesday, November 7, 2018 10:50:29 PM MST Michelle Long via Digitalmars-d-learn wrote: > On Thursday, 8 November 2018 at 02:22:42 UTC, Jonathan M Davis > > wrote: > > On Wednesday, November 7, 2018 1:03:47 PM MST Michelle Long via > > > > Digitalmars- d-learn wrote: > >> Don't let their psychobabble fool you. They are wrong and you > >> were right from the start. > > > > ... > > > >> Case A: > >> { > >> > >> if (true) goto X; > >> int x; > >> > >> } > >> X: > >> > >> > >> Case B: > >> { > >> > >> if (true) goto X; > >> { > >> > >>int x; > >> > >> } > >> > >> } > >> X: > >> > >> > >> These two cases are EXACTLY the same semantically. It's like > >> writing A + B and (A + B). > > > > That's not the situation that the OP was describing. If adding > > braces in a situation where the braces have no semantic effect > > has any impact on goto, then it's a compiler bug. It's adding a > > new scope that affects the lifetime of a variable whose > > declaration is being jumped over by a goto that matters. > > > > I know that you're frustrated, because you've hit a problem > > with goto in complex code, and you don't have a simple example > > that shows the compiler bug, but the approach that D takes with > > goto (and any construct that potentially requires code flow > > analysis) of avoiding requiring that the compiler be smart is > > precisely to reduce the risk of there being cases where the > > compiler is going to screw it up in complex code even though it > > gets it right in the simple cases. If the language required the > > compiler to be smart about such things, we'd have a lot more > > problems with subtle, hard to track down compiler bugs in > > complex code. So, we'd just have _more_ cases where people > > would be hitting frustrating bugs like you are. > > That's fine. The D compiler writers can decide to do whatever > they want. I can simply take my "business" elsewhere if I don't > like it. > > What I am talking about is about an obvious error(Ok, I haven't > produced a simplified test case but dustmite or visual D is not > working for me to do so at this point in time, but it would be > nice for sake of argument to assume I'm right...). > > > Regardless, if you want to actually have your problem fixed, > > you're going to need to provide a reproducible test case in a > > bugzilla report, even if it's large, otherwise no one is going > > to be able to track it down for you. > > That's easier said than done. I wasn't expecting anyone to be > able to fix a bug that can't be reproduced. > > What I expect is that, given my assumptions that I'm right, that > people can agree the compiler does have a bug or flaw that can > easily be fixed give then two simplified test cases basic purely > what I have done in my own code. > > 1. > > foreach(...) > { >if (x) goto Y: >int z; > } > Y: > > Fails. > > foreach(...) > { >if (x) goto Y: >{ > int z; >} > } > Y: > > Passes. > > THAT IS FACT! It doesn't matter if the examples work above. I > have simplified what I have done and in my code I simply add > brackets and it works! That is what people should be thinking > about... not test cases, MWE's, compiler versions, etc. > > Is it logical that the compiler **should** error out in the first > case and no in the second? > > That is what the discussion is ALL about. Once that is dealt with > then we can move on to finding out more specifics. There is no > reason to build the windows of a house before the foundation, > it's just far more work without any benefit. > > > Once people can say: If that is all you are doing is adding > brackets around what follows the goto and break out of > scope(which is what the code above says) and you can compile, > then it is a compiler bug or flaw. > > Once people verify that, rather than trying to create rabbit > holes, then I can do more work on finding out more specifics. > Until then, it is pointless to do anything on my side because if > people come back and say "No, it is suppose to work that way" > then what the hell am I trying to simplify and fix? It's not a > bug then. If you have code where you get a compiler error about a goto skipping the initializiation of a variable, and you add braces that should have no semantic effect on the code whatsoever, and the error goes away, then yes, that's a compiler bug. If, however, the braces do affect the semantics of the code, then that's not necessarily a compiler bug. At that point, whether it's a compiler bug or not would depend on what exactly the code was. In an example such as while(1) { if(cond) goto label; int x; } label: adding braces such as while(1) { if(cond) { goto label; } int x; } label: or while(1) { if(cond) goto label; { int x; } } label: should have no effect. However, in an example such as goto label; int x; label: adding braces such as goto label; { int x; } label: changes the
Re: is opOpAssign returning a value less than ideal ?
On Wednesday, November 7, 2018 10:45:07 PM MST Jonathan M Davis via Digitalmars-d-learn wrote: > On Wednesday, November 7, 2018 9:28:19 PM MST Codifies via Digitalmars-d- > > learn wrote: > > I noticed that opOpAsign allows you to return a value... > > > > this means I can do this (return a node from my list class when > > adding a new node) > > ``` > > anode = alist ~= > > ``` > > to me this looks a little unusual (but to be fair I can live with > > it) > > > > being as when its used like this: > > ``` > > alist ~= > > ``` > > you need to find out what the ~ operator does anyway, I don't > > think it harms readability > > > > any thoughts? > > It's common practice in C++ to have the various assignment operators > return a reference to the object being assigned to so that the operations > can be chained, and I don't see why the situation in D would be any > different. But if for whatever reason, you don't want to do the same with > your types, you can always just make those operators void. Either way, > the fact that an assignment operator returns a reference to the object > doesn't require you to then actually use it for anything. It just allows > folks to do so if they think that it's appropriate in a particular piece > of code. Sometimes, it's useful; often it isn't, but if the return type > is void, then you can't do it even in the cases where it would be useful. Rereading what you wrote, are you asking whether it's reasonable to return a value instead of a reference? Personally, I don't think that that's good design at all, but I also don't see any reason for the compiler to prevent it. Personally, I think that the default design should be to return by ref. Returning void is less than ideal but isn't necessarily bad, depending on the situation (especially if we're not talking about a general purpose library). However, I expect that returning non-void by value rather than by ref is rarely -if ever - going to be a good design choice. It's just going to be confusing and not particularly useful. - Jonathan M Davis
Re: is opOpAssign returning a value less than ideal ?
On Wednesday, November 7, 2018 9:28:19 PM MST Codifies via Digitalmars-d- learn wrote: > I noticed that opOpAsign allows you to return a value... > > this means I can do this (return a node from my list class when > adding a new node) > ``` > anode = alist ~= > ``` > to me this looks a little unusual (but to be fair I can live with > it) > > being as when its used like this: > ``` > alist ~= > ``` > you need to find out what the ~ operator does anyway, I don't > think it harms readability > > any thoughts? It's common practice in C++ to have the various assignment operators return a reference to the object being assigned to so that the operations can be chained, and I don't see why the situation in D would be any different. But if for whatever reason, you don't want to do the same with your types, you can always just make those operators void. Either way, the fact that an assignment operator returns a reference to the object doesn't require you to then actually use it for anything. It just allows folks to do so if they think that it's appropriate in a particular piece of code. Sometimes, it's useful; often it isn't, but if the return type is void, then you can't do it even in the cases where it would be useful. - Jonathan M Davis
Re: Is this a bug? +goto
On Wednesday, November 7, 2018 1:03:47 PM MST Michelle Long via Digitalmars- d-learn wrote: > Don't let their psychobabble fool you. They are wrong and you > were right from the start. ... > Case A: > { > if (true) goto X; > int x; > } > X: > > > Case B: > { > if (true) goto X; > { >int x; > } > } > X: > > > These two cases are EXACTLY the same semantically. It's like > writing A + B and (A + B). That's not the situation that the OP was describing. If adding braces in a situation where the braces have no semantic effect has any impact on goto, then it's a compiler bug. It's adding a new scope that affects the lifetime of a variable whose declaration is being jumped over by a goto that matters. I know that you're frustrated, because you've hit a problem with goto in complex code, and you don't have a simple example that shows the compiler bug, but the approach that D takes with goto (and any construct that potentially requires code flow analysis) of avoiding requiring that the compiler be smart is precisely to reduce the risk of there being cases where the compiler is going to screw it up in complex code even though it gets it right in the simple cases. If the language required the compiler to be smart about such things, we'd have a lot more problems with subtle, hard to track down compiler bugs in complex code. So, we'd just have _more_ cases where people would be hitting frustrating bugs like you are. Regardless, if you want to actually have your problem fixed, you're going to need to provide a reproducible test case in a bugzilla report, even if it's large, otherwise no one is going to be able to track it down for you. Now, a goto-related regression has recently been reported for joiner: https://issues.dlang.org/show_bug.cgi?id=19213 where some code worked with joiner in 2.081.2 but does not work with 2.082.0 or later, so you may want to test your code with an older compiler release to see if you've hit a compiler regression. If so, that could be a starting point for tracking down the problem. - Jonathan M Davis
Re: Is this a bug? +goto
On Monday, November 5, 2018 7:55:46 PM MST MatheusBN via Digitalmars-d-learn wrote: > On Tuesday, 6 November 2018 at 01:55:04 UTC, Jonathan M Davis > > wrote: > >> And I found a bit strange that in such code, since "x" is > >> never used, why it isn't skipped. > > > > It's skipped right over. The goto jumps out of the scope, and > > the line with > > > > int x; > > > > is never run. In fact, if you compile with -w or -wi, the > > compiler will give you a warning about unreachable code. > > That is exactly my point. > > Since "x" it's skipped and never used, it shouldn't just be a > warning (unreachable code) instead of an error? > > I'm trying to understand why/when such code could give any > problem. > > On the other hand if the code were: > > { > goto Q: > int x; > > Q: > x = 10; // <- Now you are accessing an uninitialized variable. > } > > Then I think an error would be ok. D tries to _very_ little with code flow analysis, because once you start having to do much with it, odds are that the compiler implementation is going to get it wrong. As such, any feature that involves code flow analysis in D tends to be _very_ simple. So, D avoids the issue here by saying that you cannot skip the initialization of a variable with goto. The compiler is not going to do the complicated logic of keeping track of where you access the variable in relation to the goto. That's exactly the sort of thing that might be obvious in the simple case but is highly likely to be buggy in more complex code. Code such as { goto Q; int x; } Q: or { if(foo) goto Q; int x; } Q: is fine, because the compiler can trivially see that it is impossible for x to be used after it's been skipped, whereas with something like goto Q; int x; Q: the compiler has to do much more complicated analysis of what the code is doing in order to determine that, and when the code isn't trivial, that can get _really_ complicated. You could argue that it would be nicer if the language required that the compiler be smarter about it, but by having the compiler be stupid, it reduces the risk of compiler bugs, and most people would consider code doing much with gotos like this to be poor code anyway. Most of the cases where goto is reasonable tend to be using goto from inside braces already, because it tends to be used as a way to more efficiently exit deeply nested code. And with D's labeled break and continue, the need for using goto outside of switch statements also tends to be lower than it is in C/C++. - Jonathan M Davis
Re: Is this a bug? +goto
On Monday, November 5, 2018 5:33:56 PM MST MatheusBN via Digitalmars-d-learn wrote: > On Tuesday, 6 November 2018 at 00:14:26 UTC, Jonathan M Davis > > wrote: > > On Monday, November 5, 2018 4:54:59 PM MST MatheusBN via > > > > Digitalmars-d-learn wrote: > >> Hi, > >> > >> I posted this in another thread but without any response. > >> > >> This code: > >> > >> void main(){ > >> > >> goto Q; > >> int x; > >> Q: > >> writeln("a"); > >> > >> } > >> > >> Gives me this error: "source_file.d(4): Error: goto skips > >> declaration of variable source.main.x at source_file.d(5)" > >> > >> > >> Now, if I add a pair of brackets: > >> > >> void main(){ > >> > >> { > >> > >> goto Q; > >> int x; > >> > >> } > >> Q: > >> writeln("a"); > >> > >> } > >> > >> It works. So Is this a bug? > > > > All the spec says on the matter is that > > > > "It is illegal for a GotoStatement to be used to skip > > initializations." > > > > https://dlang.org/spec/statement.html#goto-statement > > > > In the first case, x exists at the label Q, and its > > initialization was skipped, so it's clearly illegal. However, > > in the second case, because of the braces, x does _not_ exist > > Just to be clear, when you say "x exists at the label Q", you > mean at the same scope, right? The scope that x was at is over at the label Q. So, x doesn't exist at the label Q. It has no address at that point. It's not on the stack. It doesn't exist in any sense other than the fact that it happens to be in the source code above it. In fact, the line with x never even ran, so x _never_ existed. > That's interesting but a bit confusing isn't? I don't see why. { goto Q; int x; } Q: is basically the same thing as while(1) { break; int x; } The same thing happens in both cases. > And I found a bit strange that in such code, since "x" is never > used, why it isn't skipped. It's skipped right over. The goto jumps out of the scope, and the line with int x; is never run. In fact, if you compile with -w or -wi, the compiler will give you a warning about unreachable code. > I know it's another language but in C at least in GCC there is no > error over such code, so that's my confusion. C is a different language, and it's one that generally doesn't care much about safety. It allows all kinds of horrible things that cause bugs. The folks behind D (and the folks behind _most_ languages since C/C++) tend to prefer a greater degree of safety than C provides. - Jonathan M Davis
Re: Is this a bug? +goto
On Monday, November 5, 2018 4:54:59 PM MST MatheusBN via Digitalmars-d-learn wrote: > Hi, > > I posted this in another thread but without any response. > > This code: > > void main(){ > goto Q; > int x; > Q: > writeln("a"); > } > > Gives me this error: "source_file.d(4): Error: goto skips > declaration of variable source.main.x at source_file.d(5)" > > > Now, if I add a pair of brackets: > > void main(){ > { > goto Q; > int x; > } > Q: > writeln("a"); > } > > It works. So Is this a bug? All the spec says on the matter is that "It is illegal for a GotoStatement to be used to skip initializations." https://dlang.org/spec/statement.html#goto-statement In the first case, x exists at the label Q, and its initialization was skipped, so it's clearly illegal. However, in the second case, because of the braces, x does _not_ exist at the label Q, so its initialization was not skipped, so I don't see why it wouldn't be legal based on what the spec says, and I don't see any reason to make it illegal. Conceptually, it's doing exactly what you'd get with a break if the braces were for a loop. However, it is true that the spec could (and probably should) be more specific on the matter. - Jonathan M Davis
Re: Why use while if only iterating once ?
On Saturday, November 3, 2018 3:03:16 PM MDT Venkat via Digitalmars-d-learn wrote: > while (1) > { > FLAGS f; > switch (*p) > { > case 'U': > case 'u': > f = FLAGS.unsigned; > goto L1; > case 'l': > f = FLAGS.long_; > error("lower case integer suffix 'l' is not > allowed. Please use 'L' instead"); > goto L1; > case 'L': > f = FLAGS.long_; > L1: > p++; > if ((flags & f) && !err) > { > error("unrecognized token"); > err = true; > } > flags = cast(FLAGS)(flags | f); > continue; > default: > break; > } > break; > } > > > The last break statement prevents the loop from returned for a > second iteration. Then why use a while ? There's a continue right above the default case. So, if the code hits that point, it will loop back to the top. - Jonathan M Davis
Re: anyway to set a const object after the fact?
On Tuesday, October 30, 2018 2:18:15 AM MDT Laurent Tréguier via Digitalmars-d-learn wrote: > On Monday, 29 October 2018 at 21:50:32 UTC, aliak wrote: > > Hi, so if you have this piece of code: > > > > struct C { > > > > void f() { > > > > string[] others; > > const string[] restArgs; > > foreach (i, arg; args) { > > > > if (isValidArg(arg)) { > > > > restArgs = args[i + 1 .. $]; > > break; > > > > } > > others ~= arg; > > > > } > > // "others" is a list of args before the valid arg is > > > > encountered > > > > // "restArgs" is a list that is the args after the valid arg > > > > } > > > > } > > > > Is there anyway to set a const object after declaring it in the > > above context? > > > > Cheers, > > - Ali > > It looks like there is a Rebindable type for that in std.typecons > > : https://dlang.org/phobos/std_typecons.html#Rebindable Rebindable is specifically intentended for class references, since D doesn't really distinguish between the reference and what it's pointing to, making it impossible to under normal circumstances to have a mutable reference to a const object. On the other hand, you can easily have mutable arrays of const objects. Using Rebindable is a really a hack (albeit a very necessary one for some circumstances), and I would very much advise _against_ using it if you don't need it. Historically, it tends to run into compiler bugs, because it's trying to hack it's way around the type system, and if you're not dealing with class references, there's probably a better way to handle the problem. - Jonathan M Davis
Re: how to make '==' safe for classes?
On Sunday, October 28, 2018 12:56:10 PM MDT ikod via Digitalmars-d-learn wrote: > On Sunday, 28 October 2018 at 18:00:06 UTC, Stanislav Blinov > > wrote: > > On Sunday, 28 October 2018 at 12:38:12 UTC, ikod wrote: > >> and object.opEquals(a,b) do not inherits safety from class C > >> properties, and also I can't override it. > > > > Yep. Since Object is the base class and it defines opEquals as: > object.opEquals(a,b) even is not a Object member function, it's > free function. > > It looks a bit unnatural for me, but thanks for confirmation! It may seem weird at first, but it actually solves several problems that you get when simple calling a.obEquals(b) - the most obvious of which is that a.opEquals(b) has to worry about null, which opEquals(a, b) solves for you, but if you look at the implementation I posted elsewhere in the thread, it solves some other problems as well. It's one of those places where D was able to learn from problems that languages that came before it had. Unfortunately, the attribute problem is _not_ one of those areas. - Jonathan M Davis
Re: how to make '==' safe for classes?
On Sunday, October 28, 2018 6:38:12 AM MDT ikod via Digitalmars-d-learn wrote: > Hello > > How to make this code to compile? My goal is safe(not @trusted) > longFunction(). > > > --- > class C > { > override bool opEquals(Object o) const @safe > { > return true; > } > } > bool longFunction(C a, C b) @safe > { > return a==b; > } > void main() > { > } > --- > > > As far as I understand the problem is that AST for this code > looks like > > --- > import object; > class C : Object > { > override const @safe bool opEquals(Object o) > { > return true; > } > } > bool longFunction(C a, C b) > { > return opEquals(a, b); > } > void main() > { > return 0; > } > RTInfo!(C) > { > enum typeof(null) RTInfo = null; > > } > --- > > and object.opEquals(a,b) do not inherits safety from class C > properties, and also I can't override it. > > Is there clean way to use '==' here, or I have to convert this to > a.opEquals(b) for classes, leaving '==' for structs? > > Thanks! Because Object predats @safe (and most attributes), it really isn't compatible with them. In fact, it predates const (since it's basically the same as it was in D1) and it's only possible to compare const class objects because of a hack in the free function opEquals (which == lowers to) which casts away const (meaning that if you're not careful, you can actually violate the type system with == by mutating an object in a class' opEquals). And because attributes are inherited, even if we were willing to break existing code by changing the attributes on Object, there really isn't a good way to fix the problem, because whatever set of attributes we picked (for @safe, nothrow, const, etc.) would work for some programs but not others. That's why at one point, it was decided that we would remove all of the various member functions from Object. Given the templates in D, they really aren't necessary like they are in languages like Java. As long as stuff like the built in AA implementation is templated (which it unfortunately is not right now), all of the appropriate information can be inferred, and it's not necessary to have a root class object with member functions like opEquals in order to use it in generic code. https://issues.dlang.org/show_bug.cgi?id=9769 https://issues.dlang.org/show_bug.cgi?id=9770 https://issues.dlang.org/show_bug.cgi?id=9771 https://issues.dlang.org/show_bug.cgi?id=9772 However, while that decision was made some time ago, actually implementing it isn't easy, and the necessary steps have never happened - to the point that it doesn't seem very likely at this point. What seems far more likely is a DIP that Andrei has proposed: https://github.com/andralex/DIPs/blob/ProtoObject/DIPs/DIP.md It will introduce ProtoObject as a new root object below Object which does not have any member functions or an embedded monitor object (which is only necessary if you actually have synchronized functions). Object would stay the default base class (since code would break otherwise), and any code using Object would unfortunately continue to have the same problems, but classes that then explicitly derive from ProtoObject would be able to define opEquals, opCmp, toString, etc. with the signatures that were appropriate to the applications or libraries that they're in. Any classes derived from such classes would then be stuck with those attributes just like we're stuck with the attributes on Object right now, but those choices would then be per object hierarchy rather than forced on everyone using the language. So, it looks like that's probably going to be the ultimate fix for this problem, but we don't really have an ETA at the moment. So, unfortunately, for now, you're going to have to use @trusted with == on classes, as stupid as that is, though as a workaround, you could always create an @trusted wrapper function that just called ==. It would still be annoying, but it would be cleanly restricted the @trusted bits. - Jonathan M Davis
Re: how to make '==' safe for classes?
On Sunday, October 28, 2018 12:17:41 PM MDT Neia Neutuladh via Digitalmars- d-learn wrote: > On Sun, 28 Oct 2018 18:00:06 +, Stanislav Blinov wrote: > > On Sunday, 28 October 2018 at 12:38:12 UTC, ikod wrote: > >> and object.opEquals(a,b) do not inherits safety from class C > >> properties, and also I can't override it. > > > > Yep. Since Object is the base class and it defines opEquals as: > > ``` > > bool opEquals(Object); > > ``` > > > > the compiler rewrites `a == b` as > > `(cast(Object)a).opEquals(cast(Object)ob)`, i.e. it inserts a @system > > call into your code. > > More pedantically, it rewrites it as: > > (a is b) || > (a !is null && (cast(Object)a).opEquals(cast(Object)b)) > > An object might not be equal to itself via opEquals, but it will always > compare equal to itself with ==. Technically, it calls the free function opEquals in object.d, which does more than that (including introduce a hack to work around the type system to allow comparing const objects). Specifically, the current implementation is bool opEquals(Object lhs, Object rhs) { // If aliased to the same object or both null => equal if (lhs is rhs) return true; // If either is null => non-equal if (lhs is null || rhs is null) return false; // If same exact type => one call to method opEquals if (typeid(lhs) is typeid(rhs) || !__ctfe && typeid(lhs).opEquals(typeid(rhs))) /* CTFE doesn't like typeid much. 'is' works, but opEquals doesn't (issue 7147). But CTFE also guarantees that equal TypeInfos are always identical. So, no opEquals needed during CTFE. */ { return lhs.opEquals(rhs); } // General case => symmetric calls to method opEquals return lhs.opEquals(rhs) && rhs.opEquals(lhs); } / * Returns true if lhs and rhs are equal. */ bool opEquals(const Object lhs, const Object rhs) { // A hack for the moment. return opEquals(cast()lhs, cast()rhs); } - Jonathan M Davis
Re: Error: non-shared method core.sync.condition.Condition.notify is not callable using a shared object
On Thursday, October 18, 2018 4:50:18 AM MDT Paolo Invernizzi via Digitalmars-d-learn wrote: > There's a rational behind the fact that there's not a 'shared' > version of notify/wait method in Condition? > > Thanks, > Paolo The original author of the stuff in core.sync didn't want to update it for shared when shared was first introduced, because he didn't think that it was well enough defined yet (e.g. there was discussion over whether it should have write barriers or not). Some work has been done to improve shared support in there since then but not enough. shared _does_ still need need some rough edges sorted out (it's supposed to guarantee that you can't do any operations on it that isn't thread-safe, but while many operations are illegal, some which should be aren't, and some of the finer details likely need to be cleaner up). The basics of shared have been in place and working fine for nearly a decade, but because we've been waiting for the finer details to be finished, and it's never been a high enough priority for that to happen, stuff like core.sync has suffered. It doesn't help that the vast majority of D programs don't need to do much with shared, and those that D use higher level mechanisms such as std.concurrency or use something like the framework that vibe.d provides. However, as annoying as it is, with some extra casting, the pieces of core.sync that haven't been updated properly _can_ be used with shared. shared in general requires unsafe casting and always will. There really isn't any way around that, but the parts of core.sync that don't use shared properly will require that much more of it, unfortunately. There's no question though that the situation with core.sync needs to be fixed. Some of it has been worked on, but nowhere near enough. - Jonathan M Davis
Re: custom sorting of lists ?
On Saturday, October 13, 2018 6:52:05 PM MDT Steven Schveighoffer via Digitalmars-d-learn wrote: > You can't quick-sort a list. You can merge sort it, and it's O(nlgn). > > I'll work on getting a sort routine into Phobos for it, but I don't know > what the appropriate location for it is, as a member or along-side > std.algorithm.sort. Unless there's something about the implementation that's tied to the list itself, I would think that it would make more sense to make it a generic algorithm, then it will work with any non-random-access range, and it avoids needing to reimplement it for similar circumstances. IMHO, it really only makes sense to tie it to the container if the implementation itself needs to be for some reason. - Jonathan M Davis
Re: Why are 2-D arrays reversed?
On Wednesday, October 10, 2018 4:26:40 PM MDT Chris Katko via Digitalmars-d- learn wrote: > On Wednesday, 10 October 2018 at 16:00:42 UTC, Steven > > Schveighoffer wrote: > > On 10/10/18 9:22 AM, Chris Katko wrote: > >> int[][] data = > >> > >> [ > >> [1, 0, 1, 0, 0], > >> [1, 0, 1, 0, 0], > >> [1, 0, 1, 1, 1], > >> [1, 0, 0, 1, 0], > >> [5, 1, 1, 1, 0] > >> ]; > >> > >> when drawn with data[i][j], prints the transpose of "data": > >> > >> [1, 1, 1, 1, 5] > >> [0, 0, 0, 0, 1] > >> [1, 1, 1, 0, 1] > >> [0, 0, 1, 1, 1] > >> [0, 0, 1, 0, 0] > >> > >> So, if I flip [i][j] and print a row of "j's", it'll be > >> correct. It's very confusing and counter-intuitive to have to > >> remember to swap i and j every time I use an array. > >> > >> I guess when I load data from files, the i/j are already > >> swapped and stay consistent, but when using an array in source > >> code, they have to be flipped. > > > > I'm not sure what code you are using, but it prints out just > > fine for me: > > > > https://run.dlang.io/is/hrA0tj > > > > -Steve > > Ah, here's a simple example: > > int[][] data3 = > [ > [1, 0, 1, 0, 0], > [1, 0, 1, 0, 0], > [1, 0, 1, 1, 1], > [1, 0, 0, 1, 0], > [5, 1, 1, 1, 0] > ]; > > for(int i = 0; i < 5; i++) > { > for(int j = 0; j < 5; j++) > { > write(data4[i][j]," "); > } > writeln(); > } > >1 0 1 0 0 >1 0 1 0 0 >1 0 1 1 1 >1 0 0 1 0 >5 1 1 1 0 > > I have to draw j's first. I have to iterate through the > "y"/columns/j to get the the "x's" first. > > I mean, I guess it makes sense if the outer-most array indexer > refers to the inner-most "element". > > Wait, this IS the same as C, isn't it? So maybe this is just a > "new" problem for me since I rarely-if-ever use hardcoded > arrays... > > Maybe my brain is just melting. The situation is bascially the same as C, though trying to make the type syntax more consistent by putting it all on the left-hand side of the variable has made things more confusing. The types read basically the same as in C. The primary difference is that in D, the static array sizes go with the type and not the variable name, which means that they're on the left-hand side rather than the right. So, you get int[5][4] arr; instead of int arr[4][5]; In both cases, the type is read outward from the variable name (which is basically how the compiler reads types in both C and D, though understanding that is more critical in C because of C's function pointer syntax). It's just that in the D case, this then seems backwards, because when you then index the array, the left index has $ of 4 and the right has $ of 5, which is the reverse of the order in the declaration, whereas in C, the order matches, because the sizes went on the right-hand side. One sort of consistency was traded for another. With dynamic arrays, the sizes are always given on the right-hand side, so you don't get that reversal. So, what D does is reasonably consistent and matches C in terms of how types are read, but it does end up being annoyingly hard to wrap your head around, because the result is that the sizes of multi-dimensional, static arrays are then declared in the opposite order from the order that they're accessed in. If it weren't for the fact that D does out-of-bounds checking for all array accesses in @safe code or when -release is not used, it would likely to be a huge problem with such arrays in practice. Fortunately, since the checks are almost always in place, the inevitable mistakes are usually quickly caught. - Jonathan M Davis
Re: Compile time sequences
On Thursday, October 4, 2018 5:44:55 AM MDT drug via Digitalmars-d-learn wrote: > I was incorrect with description of the problem. The problem is that > there is no simple way to distinct types and symbols if symbols are > private. Because private symbol is not accessible you can not get any > info on it, including is it type or symbol or value. And you can not get > protection for types and values, because they have no protection at all. > So you can not get protection for types and values and can not check if > alias is type, value and symbol because it is private/protected. Vicious > circle. > > Specific case https://run.dlang.io/is/CAoxXO > > Honestly, if `isType` can recognize private members the problem would be > solved. But I think `isSymbol` and `isValue` (working with private > members) will make situation more consistent. > > > Current workaround with fields is using FieldNameTuple. But I fails to > work around private enums. It's a known issue that you can't properly do type introspection on private symbols from other modules, and it needs to be fixed in the language. It shouldn't be possible to actually use private symbols from other modules, but it should be possible to get type information on them. In his dconf talk this year, Andrei discussed adding wrappers around all of the various traits that present the type information as a set of structs so that you can easily and consistently get at it all instead of having to piece it all together like you do now. He has a partial prototype, though I don't know if he's made it public aside from what he showed in his sides, and it's just wrapping the current stuff, so it's not addding any information, just better organizing it. However, to get where he wants to go with it, problems like this with private symbols are pretty much going to have to be solved. Either way, the access level issues are a language issue and not something that can be fixed by std.traits. - Jonathan M Davis
Re: Dlang tour - Unittesting example
On Tuesday, October 2, 2018 3:59:28 AM MDT bauss via Digitalmars-d-learn wrote: > On Tuesday, 2 October 2018 at 04:13:01 UTC, Joe wrote: > > There appears to be a problem with the example at > > > > https://tour.dlang.org/tour/en/gems/unittesting > > > > If compiled with -unittest, the resulting program crashes. It > > happens with ldc2 on Linux but it can also be seen if you click > > on "Export" and run it with dmd -unittest. > > I think it's more likely a problem with your OS. > > I am unable to reproduce that with either of dmd or ldc. IIRC, we use stdc for formatting floating values and not pure D code (because correctly converting floating point values to strings is really, really complicated to implement). So, the result is going to depend on the system that it's run on. It fails on my system (64-bit FreeBSD). Honestly, this is basically the same thing as comparing floating point values with ==. You shouldn't do it. So, I'd argue that it's just plain a bad example. - Jonathan M Davis
Re: How to convert this function into a template ?
On Tuesday, October 2, 2018 6:09:53 AM MDT Vinod K Chandran via Digitalmars- d-learn wrote: > On Tuesday, 2 October 2018 at 11:49:06 UTC, Jonathan M Davis > > wrote: > > Why do you have a function for that? All you need to do is use > > the append operator. e.g. > > > > x ~= value; > > > > - Jonathan M Davis > > Thanks for the reply. I did not find that it in documentation. > Ofcourse i lost a chance to learn about templates. By translating > a well known function into a template, i can easiy learn the > concept, since the template documentation is little bit hard to > understand. The template equivalent would have been something like void arrayAdd(T)(ref T[] x, T value) { auto index = x.length; x.length += 1; x[index] = value; } But if you're new to the language, I'd suggest that you read this site / book: http://ddili.org/ders/d.en/index.html - Jonathan M Davis
Re: How to convert this function into a template ?
On Tuesday, October 2, 2018 5:40:18 AM MDT Vinod K Chandran via Digitalmars- d-learn wrote: > Hi all, > I have a function and i want to convert this into a template so > that i can use this function for more than one data type. > This is my function. > ```D > void ArrayAdd( ref int[] x, int value) { > int index = x.length ; > x.length += 1 ; > x[index] = value ; > } > ``` Why do you have a function for that? All you need to do is use the append operator. e.g. x ~= value; - Jonathan M Davis
Re: Can I create static c callable library?
On Thursday, September 27, 2018 6:16:13 AM MDT Atila Neves via Digitalmars- d-learn wrote: > On Tuesday, 25 September 2018 at 14:13:50 UTC, Jacob Carlborg > > wrote: > > On Tuesday, 25 September 2018 at 12:05:21 UTC, Jonathan M Davis > > > > wrote: > >> If you use -betterC, then it's trivial, because your D program > >> is restricted to extern(C) functions and features which don't > >> require druntime. It can also be done without -betterC (and > >> thus with druntime), but it gets to be _way_ more of a pain, > >> because it requires that you manually initialize druntime - > >> either by forcing whatever is using your "C" library to call a > >> specific function to initialize druntime before using any of > >> its normal functions or by having every function in the > >> library check whether druntime has been initialized yet and > >> initialize it if it hasn't been before it does whatever it's > >> supposed to do. > > > > Shouldn't it be possible to use a C initialization function, > > i.e. pragma(crt_constructor) to initialize druntime? Then it > > only needs to be initialized once and it's not required to > > check if it's initialized all the time. > > > > -- > > /Jacob Carlborg > > Even easier, compile this C file and add the resulting object > file to your (now mostly) D static library: > > --- > extern int rt_init(void); > extern int rt_term(void); > > __attribute__((__constructor__)) void dinit(void) { > rt_init(); > } > __attribute__((__destructor__)) void dterm(void) { > rt_term(); > } > --- > > The C runtime will initialise the D runtime for you. That's a neat trick. - Jonathan M Davis
Re: Is there a way to use Object.factory with templated classes? Or some way to construct templated classes given RTTI of an instance?
On Thursday, September 27, 2018 2:44:25 AM MDT Chad Joan via Digitalmars-d- learn wrote: > The spec seems to have the homogeneous cases covered: classes > with classes or structs with structs. What I'm more worried > about is stuff like when you have a class compared to a struct or > builtin type, or maybe a struct compared to a builtin type > (especially more complicated builtin types like arrays!). The > homogeneous cases are important for making a type consistent with > itself, but the other cases are important for integrating a type > with everything else in the ecosystem. > > Notably, "alias this" is awesome and has more or less solved that > for me in the pedestrian cases I tend to encounter. I can write > a struct and alias this to some reference variable that will be > representative of my struct's "nullness" or other states of > existence. > > But I wouldn't be surprised if there are corner-cases I haven't > encountered yet (actually I think I just remembered that this bit > me a little bit once or twice) where having a single alias-this > isn't sufficient to cover all of the possible things my > struct/class could be compared to (ex: if the type's null-state > corresponded to int.max for ints and float.nan for floats, and > you can't just use opEquals, such as when the type is a class and > could be precisely null). For two types to be compared, they must be the the same type - or they must be implicitly convertible to the same type, in which case, they're converted to that type and then compared. So, as far as D's design of comparison goes, there is no need worry about comparing differing types. At most, you need to worry about what implicit type conversions exist, and D isn't big on implicit type conversions, because they tend to cause subtle bugs. So, while they definitely affect comparison, they don't affect anywhere near as much as they would in a language like C++. In general, you're not going to get very far if you're trying to make it possible to compare a user-defined type against other types in D without explicitly converting it first. - Jonathan M Davis
Re: Is there a way to use Object.factory with templated classes? Or some way to construct templated classes given RTTI of an instance?
On Thursday, September 27, 2018 1:41:23 AM MDT Chad Joan via Digitalmars-d- learn wrote: > On Thursday, 27 September 2018 at 05:12:06 UTC, Jonathan M Davis > This is also reminding me of how it's always bugged me that there > isn't a way to operator overload opEquals with a static method > (or even a free function?), given that it would allow the > class/struct implementer to guard against (or even interact > intelligently with) null values: That's not really an issue with D. With classes, when you have a == b, it doesn't lower to a.opEquals(b). Rather, it lowers to opEquals(a, b), and the free function opEquals is defined as bool opEquals(Object lhs, Object rhs) { // If aliased to the same object or both null => equal if (lhs is rhs) return true; // If either is null => non-equal if (lhs is null || rhs is null) return false; // If same exact type => one call to method opEquals if (typeid(lhs) is typeid(rhs) || !__ctfe && typeid(lhs).opEquals(typeid(rhs))) /* CTFE doesn't like typeid much. 'is' works, but opEquals doesn't (issue 7147). But CTFE also guarantees that equal TypeInfos are always identical. So, no opEquals needed during CTFE. */ { return lhs.opEquals(rhs); } // General case => symmetric calls to method opEquals return lhs.opEquals(rhs) && rhs.opEquals(lhs); } / * Returns true if lhs and rhs are equal. */ bool opEquals(const Object lhs, const Object rhs) { // A hack for the moment. return opEquals(cast()lhs, cast()rhs); } So, it already takes care of checking for null or even if the two references point to the same object. For structs, a == b, does lower to a.opEquals(b), but for better or worse, structs are designed so that their init values need to be valid, or you're going to have problems in general. Trying to work around that is fighting a losing battle. > Wouldn't it be helpful to have a root class type just to have a > "Top" type at runtime, even if it had no members? Ex: so you > could do things like make an array ProtoObject[] foo; that can > contain any runtime polymorphic variables. Maybe? It's not something that I've personally found to be particularly useful. Once you can templatize code, the need to have a common base class gets pretty hard to argue for, but I don't know that it's non-existent. Also, for better or worse, you can already get it with void* - and cover more types no less (albeit less @safely). But from what I understand of what Andrei is intending, ProtoObject will end up being the new root class for all D classos, so having ProtoObject[] would work for all extern(D) classes. Of course, that still potentially leaves exern(C++) classes and interfaces (which could be extern(C++) or COM even right now and aren't derived from Object). So, things are already a bit weird with classes when you start interacting with other languages through D. is(T : Object) and is(T == class) do _not_ mean quite the same thing even though you'd think that they would. And I haven't done enough with extern(C++) or COM in D to claim to understand all of the subtleties. If you're not messing with them directly or writing generic code that's going to mess with them, it doesn't really matter though. -Jonathan M Davis
Re: Is there a way to use Object.factory with templated classes? Or some way to construct templated classes given RTTI of an instance?
On Wednesday, September 26, 2018 10:20:58 PM MDT Chad Joan via Digitalmars- d-learn wrote: > On Wednesday, 26 September 2018 at 23:32:36 UTC, Jonathan M Davis > > wrote: > > On Wednesday, September 26, 2018 3:24:07 PM MDT Adam D. Ruppe > > > > via Digitalmars-d-learn wrote: > >> Object.factory kinda sux and I'd actually like to remove it > >> (among other people). There's no plan to actually do that, but > >> still, just on principle I want to turn people away. > > > > While there may not currently be plans to be remove it, as > > there _are_ plans to add ProtoObject as the new root class > > underneath Object, at some point here, it's likely that a large > > percentage of classes won't have anything to do with Object, so > > relying on Object.factory to be able to construct class Objects > > in general isn't likely to be a viable path in the long term - > > though presumably it would work for a code base that's written > > specifically with it in mind. > > > > Personally, I'm hoping that we eventually get to the point > > where Walter and Andrei are willing to outright deprecate > > Object itself, but I expect that ProtoObject will have to have > > been in use for a while before we have any chance of that > > happening. Either way, I think that it's clear that most code > > bases should go with a solution other than Object.factory if at > > all reasonably possible. > > > > - Jonathan M Davis > > That's interesting! Thanks for mentioning. > > If you don't mind, what are the complaints regarding Object? Or > can you link me to discussions/issues/documents that point out > the shortcomings/pitfalls? > > I've probably run into a bunch of them, but I realize D has come > a long way since that original design and I wouldn't be surprised > if there's a lot more for me to learn here. I can point you to the related DIP, though it's a WIP in progress https://github.com/andralex/DIPs/blob/ProtoObject/DIPs/DIP.md There are also these enhancement requests for removing the various member functions from Object (though they're likely to be superceded by the DIP): https://issues.dlang.org/show_bug.cgi?id=9769 https://issues.dlang.org/show_bug.cgi?id=9770 https://issues.dlang.org/show_bug.cgi?id=9771 https://issues.dlang.org/show_bug.cgi?id=9772 Basically, the problems tend to come in two areas: 1. Because of how inheritance works, once you have a function on a class, you're forcing a certain set of attributes on that function - be it type qualifiers like const or shared or scope classes like pure or @safe. In some cases, derived classes can be more restricted when they override the function (e.g. an overide can be @safe when the original is @system), but that only goes so far, and when you use the base class API, you're stuck with whatever attributes it has. Regardless, derived classes can't be _less_ restrictive. In fact, the only reason that it's currently possible to use == with const class references in D right now is because of a hack. The free function opEquals that gets called when you use == on two class references actually casts away const so that it can then call the member function opEquals (which doesn't work with const). So, if the member function opEquals mutates the object, you actuall get undefined behavior. And because Object.opEquals defines both the parameter and invisible this parameter as mutable, derived classes have to do the same when they override it; otherwise, they'd be overloading it rather than overriding it. Object and its member functions really come from D1 and predate all of the various attributes in D2 - including const. But even if we could just add all of the attributes that we thought should be there without worrying about breaking existing code, there would be no right answer. For instance, while in the vast majority of cases, opEquals really should be const, having it be const does not work with types that lazily initialize some members (since unlike in C++, D does not have backdoors for const - when something is const, it really means const, and it's undefined behavior to cast away const and mutate the object). So, having Object.opEquals be const might work in 99% of cases, but it wouldn't work in all. The same could be said for other attributes such as pure or nothrow. Forcing a particular set of attributes on these functions on everyone is detrimental. And honestly, it really isn't necessary. Having them on Object comes from a Java-esque design where you don't have templates. With proper templates like D2 has, there normally isn't a reason to operate on an Object. You templatize the code rather than relying on a common base class. So, there's no need to have Object.toString in order have toString for all classes or Object.opEquals to have opEquals for all classes. Each class can define it however it sees fit. Now, once a particular class in a hierarchy has defined a function like opEquals or toString, that affects any classes derived from it, but then only the
Re: Is there a way to use Object.factory with templated classes? Or some way to construct templated classes given RTTI of an instance?
On Wednesday, September 26, 2018 3:24:07 PM MDT Adam D. Ruppe via Digitalmars-d-learn wrote: > Object.factory kinda sux and I'd actually like to remove it > (among other people). There's no plan to actually do that, but > still, just on principle I want to turn people away. While there may not currently be plans to be remove it, as there _are_ plans to add ProtoObject as the new root class underneath Object, at some point here, it's likely that a large percentage of classes won't have anything to do with Object, so relying on Object.factory to be able to construct class Objects in general isn't likely to be a viable path in the long term - though presumably it would work for a code base that's written specifically with it in mind. Personally, I'm hoping that we eventually get to the point where Walter and Andrei are willing to outright deprecate Object itself, but I expect that ProtoObject will have to have been in use for a while before we have any chance of that happening. Either way, I think that it's clear that most code bases should go with a solution other than Object.factory if at all reasonably possible. - Jonathan M Davis
Re: Can I create static c callable library?
On Tuesday, September 25, 2018 5:03:11 AM MDT John Burton via Digitalmars-d- learn wrote: > I need to write a library to statically link into a c program. > Can I write this library in D? > Will I be able to use proper D abilities like gc? Obviously the > public interface will need to be basic c callable functions... > > I 'main' is a c program will this work? If you use -betterC, then it's trivial, because your D program is restricted to extern(C) functions and features which don't require druntime. It can also be done without -betterC (and thus with druntime), but it gets to be _way_ more of a pain, because it requires that you manually initialize druntime - either by forcing whatever is using your "C" library to call a specific function to initialize druntime before using any of its normal functions or by having every function in the library check whether druntime has been initialized yet and initialize it if it hasn't been before it does whatever it's supposed to do. And of course, if you pass any GC-allocated memory out of the library, you have to worry about calling all of the appropriate GC functions so that it knows not to free it and knowing when to tell the GC that that memory can be freed. It's all very feasible and all very annoying. In general, it's far, far easier to write D programs that call into C code than to write C programs that call into D code. That's part of why some folks are so excited about -betterC. It makes it _way_ easier to write D libraries that can be called from C or C++ - though because you lose out on so many D features in the process (like the GC), whether it's even worth it is highly debatable. - Jonathan M Davis
Re: Is it possible to translate this API's C headers?
On Tuesday, September 18, 2018 7:39:40 AM MDT Atila Neves via Digitalmars-d- learn wrote: > On Monday, 17 September 2018 at 19:13:06 UTC, Jonathan M Davis > > wrote: > > On Monday, September 17, 2018 7:43:21 AM MDT Kagamin via > > > > Digitalmars-d-learn wrote: > >> try dpp https://github.com/atilaneves/dpp > > > > Since according to Mike's post, it's C++ code, dpp wouldn't > > help, because it currently only supports C and not C++. > > > > - Jonathan M Davis > > It does C++ as well, just not all (or even close at this point) > of it. I doubt it'd work on any real C++ codebase right now, but > who knows. It definitely won't if any of the headers use the > standard library, which is likely to happen. Well, the repo claims that it currently only does C - hence why I said that it will only do C (though even if it partially supports C++, odds are it's not enough to matter unless you know what you're doing - which the OP clearly doesn't, since they don't know C/C++). > It turns out that parsing C++ is a lot of work. Who knew? :P Yeah... - Jonathan M Davis
Re: Is it possible to translate this API's C headers?
On Monday, September 17, 2018 7:43:21 AM MDT Kagamin via Digitalmars-d-learn wrote: > try dpp https://github.com/atilaneves/dpp Since according to Mike's post, it's C++ code, dpp wouldn't help, because it currently only supports C and not C++. - Jonathan M Davis
Re: Pass 'this' as reference
On Saturday, September 15, 2018 11:44:05 AM MDT Jan via Digitalmars-d-learn wrote: > On Thursday, 13 September 2018 at 11:08:30 UTC, Jonathan M Davis > > wrote: > > [...] > > Thanks for clarifying Jonathan :) > But aren't the variables considered rvalues then? No. variables are _always_ lvalues. An lvalue is an object which is addressable and which can therefore be assigned a value (ignoring issues of constness). The name comes from the fact that lvalues are allowed on the left-hand side of an assignment operation, whereas rvalues are only allowed on the right. e.g. int i; int* p; are both lvalues. They have addresses and can be assigned to. i = 42; p = auto p2 = On the other hand, the return value of int foo(string s); is an rvalue. How it's actually stored is compiler-defined; you can't take its address, and you can't assign to it. foo("bar") = 42; // illegal auto p = ("bar"); // illegal On the other hand, ref int foo(string s); returns by ref, so it's returning an lvalue. Its address can be taken, and it can be assigned a value. foo("bar") = 42; // legal auto p = ("bar"); // legal Because a pointer or reference points to a specific address, even if the pointer itself is an rvalue, what it points to is almost always an lvalue, (the main case where it isn't an lvalue would be something like a function pointer, since you can take a function's address, but you can't assign to it). So, something like int* foo(string s); *foo("bar") = 42; compiles. However, ultimately, you can't know whether a particular value is an lvalue or rvalue without context. A variable is always an lvalue, whereas a return value usually isn't - but it can be if it's returned by ref. And a variable and return value could both be the same type - int, int*, string, etc. So, the type itself doesn't tell you whether something is an lvalue or rvalue. It's how it's stored that tells you. Ultimately though, if you want to know whether something is an lvalue or rvalue, consider whether it's something that can go on the left-hand side of an assignment operation (ignoring its constness), or whether it can only go on the right-hand side. https://msdn.microsoft.com/en-us/library/f90831hc.aspx https://stackoverflow.com/questions/17357888/exact-difference-between-rvalue-and-lvalue https://www.quora.com/What-is-lvalue-and-rvalue-in-C - Jonathan M Davis
Re: dealing with very long paths and names
On Saturday, September 15, 2018 8:45:55 AM MDT Vladimir Panteleev via Digitalmars-d-learn wrote: > On Friday, 14 September 2018 at 21:16:31 UTC, Jonathan M Davis > > wrote: > > Yeah, though if you write cross-platform applications or > > libraries (and ideally, most applications and libraries would > > be platform-agnostic), you can't necessarily avoid all of the > > Windows insanity, even if you yourself use a platform without > > those problems. > > Linux generally allows you to go ahead and use the filesystem as > a database, and this works pretty well in a lot of cases. > Filesystem performance is much better, and so are the limitations > - not just the path length as discussed in this thread, but also > the range of valid characters (anything except / and NUL is > fine). Plus, depending on your choice of filesystem, you get > bonus features like snapshots, incremental backups, and > deduplication. It's a boon for prototyping (or Linux-only > software). Oh, I don't disagree. I think that in general it makes _way_ more sense to use a *nix system for development (or most anything else) even if the software can run on multiple platforms. And actually, the primary reason that I use the OS I do (FreeBSD) is because of the filesystem (it has first class ZFS support unlike Linux). However, I'm a strong believer that in general, software should be cross-platform if it reasonably can be. That's usually the worst when folks use all kinds of Windows-specific stuff when they don't need to, but sometimes, Linux-isms do creep into code unnecessarily. Either way, while I've occasionally found something that Windows did better than *nix, far more often, it's shocking how bad their APIs are. And in this particular case, there really isn't a great solution. Trying to hide the Windows limitations by translating longer paths so that the Windows API is risky business, but leaving it up to the programmer to run into it and then scream in frustration like the OP is isn't great either. And of course, even if they outright fixed the problem in Windows tomorrow, it would probably be over a decade before you could rely on it given how long people use older versions of Windows. - Jonathan M Davis
Re: array to string functional?
On Friday, September 14, 2018 11:39:48 PM MDT berni via Digitalmars-d-learn wrote: > On Saturday, 15 September 2018 at 03:25:38 UTC, Paul Backus wrote: > > On Friday, 14 September 2018 at 20:43:45 UTC, SrMordred wrote: > >> What you want is std.range.chunks > >> > >> > >> auto a = [1,0,1,1,1,0,1,0,1,1,1,1,0]; > >> > >> a.map!(to!string) > >> > >> .join("") > >> .chunks(4) > >> .map!(to!string) //don´t know why the chunks are not > >> > >> already strings at this point ;/ > >> > >> .writeln; > > > > It's easier if you chunk before joining: > > > > auto a = [1,0,1,1,1,0,1,0,1,1,1,1,0]; > > > > a.map!(to!string) > > > > .chunks(4) > > .map!join > > .writeln; > > Oh, thanks. What I didn't know about was join. Now I wonder how I > could have found out about it, without asking here? Even yet I > know it's name I cannot find it, nighter in the language > documentation nor in the library documentation. https://dlang.org/phobos/std_array.html#join - Jonathan M Davis
Re: dealing with very long paths and names
On Friday, September 14, 2018 2:52:42 PM MDT H. S. Teoh via Digitalmars-d- learn wrote: > On Fri, Sep 14, 2018 at 07:05:35PM +, Basile B. via Digitalmars-d- learn wrote: > > On Friday, 14 September 2018 at 17:59:38 UTC, Josphe Brigmo wrote: > > > Seems to break dirEntries when trying to deal with long pathnames(> > > > 512) on windows. > > > > > > It's a strange error because it just fails with access denied or > > > missing file. > > > > The bug is known, see https://issues.dlang.org/show_bug.cgi?id=8967 > > Whoa. After seeing the insane mess that is the Windows pathname syntax, > I'm so glad I code on Linux instead! Yeah, though if you write cross-platform applications or libraries (and ideally, most applications and libraries would be platform-agnostic), you can't necessarily avoid all of the Windows insanity, even if you yourself use a platform without those problems. - Jonathan M Davis
Re: Pass 'this' as reference
On Thursday, September 13, 2018 4:04:58 AM MDT Jan via Digitalmars-d-learn wrote: > Many thanks Adam and Steve! Works like a charm! :D > I presumed classes are lvalues. I shouldn't make things more > complicated than they are ;-) Well, the variables _are_ lvalues. It's just that they're references to objects rather than the objects themselves. You never refer to a class object directly in D. Rather, you're always dealing with a reference to a class object. Class references are basically pointers except that you can't dereference them directly, just call member functions on them (which in D means implicitly dereferencing whether you're talking about pointers or class references). In that respect, they're like classes in Java. So, if you assign a value to a class reference, you're assigning the reference, not the class object itself, just like when you assign a value to a pointer, you're mutating the pointer itself, not mutating the object that it points to. - Jonathan M Davis
Re: Shared, ref, arrays, and reserve template instantiation
On Wednesday, September 12, 2018 9:42:19 PM MDT James Blachly via Digitalmars-d-learn wrote: > Neia is right that I tried to cast as in the second case ( but > without UFCS -- reserve( cast(int[]), N); ). As an aside, what > is going on behind the scenes with the compiler when casting away > a property? I did not think cast operations copied data, so was > surprised that a cast value is not an lvalue. Well, you basically get a temporary variable when you cast an object, and those are rvalues. And while casting with regards to type qualifiers such as const or shared, you're not actually changing the data, plenty of other casts do - e.g. float and long don't even have the same size, but you can cast from one to the other. So, even in principle, only some casts could result in lvalues even if we wanted them to. - Jonathan M Davis
Re: Shared, ref, arrays, and reserve template instantiation
On Wednesday, September 12, 2018 5:41:16 PM MDT James Blachly via Digitalmars-d-learn wrote: > When I add the "shared" attribute to an array, I am no longer > able to call reserve because the template won't instantiate: > > Error: template object.reserve cannot deduce function from > argument types !()(shared(int[]), int), candidates are: > /dlang/dmd/linux/bin64/../../src/druntime/import/object.d(4091): >object.reserve(T)(ref T[] arr, size_t newcapacity) > > 1. Shared modifies the type, so the template does not match. Even > casting does not seem to work however. Is there something about > shared that makes it unable to be taken by reference? > 2. Is there a workaround for me to be able to preallocate the > array? You can't do much of anything with shared while it's shared, which is pretty much the whole point. The way that shared needs to be used in general is essentially synchronized(mutexForSharedObj) { auto local = cast(Type)sharedObj; // do stuff with local... // ensure that no thread-local references to local / sharedObj exist // before releasing the mutex } // shared object is now essentially unusable again Doing pretty much _any_ operation on a shared object while it's shared (other than atomic operations from core.atomic) is wrong, because it's not thread-safe. The compiler prevents most operations but not as many as it should (e.g. copying is currently legal). That will likely be fixed in the future, but exactly what's going to happen to shared in all of the fine details hasn't been sorted out yet. The basics work, but not all of the details are as they should be yet. So, if you're doing anything like calling reserve or ~= on a shared array, then you need to protect it with the mutex that you have for it and cast away shared first. However, if you're just dealing with constructing the array, then what you should do is create it as thread-local and then cast it to shared after you're done setting it up and are ready to share it across threads (after which, all further operations on it should be protected by a mutex or use atomics, otherwise they're not thread-safe). - Jonathan M Davis
Re: Bug with writeln?
On Sunday, September 9, 2018 8:30:12 AM MDT Saurabh Das via Digitalmars-d- learn wrote: > Thank you for explaining all this. > > It is frustrating because the behaviour is very counterintuitive. > > I will use a workaround for now. Ranges are fantastic, and the basic concept is solid, but a number of the implementation details really weren't worked out well enough in the beginning, which means that there's a lot of stuff that works reasonably well with ranges but falls apart on some level in certain circumstances - and what happens when ranges get copied is a big part of that. On some level, it's what we get for being the first language to really implement ranges as part of its standard library. As I understand it, Andrei didn't create the concept, but AFAIK, it wasn't implemented on any real scale by anyone prior to them being added to Phobos. And when you're the first to implement something, you often screw it up on some level. With many things, D was able to learn from C++ and improve, but this is an area where we got to make new mistakes. The result is something that's extremely useful and largely works but which has some problematic corner cases that really shouldn't be there. - Jonathan M Davis
Re: "immutable string" vs "const string*"
On Sunday, September 9, 2018 2:49:56 AM MDT rikki cattermole via Digitalmars-d-learn wrote: > On 09/09/2018 8:41 PM, Christian Mayer wrote: > > On Sunday, 9 September 2018 at 08:14:41 UTC, rikki cattermole wrote: > >> Are you aware that a string is just an alias of immutable(char)[]? > > > > Yes, I'm aware of that. But it's the same, for example, with just one > > char. "immutable char" vs "const char*". > > > > Or int, or any other data type. As of my current understanding "char" > > will create a new variable and copy the content of the original to the > > new variable. "char*" will just use the pointer. And "const char*" is > > good for when not modifying. But I also can achieve the same using > > "immutable char". But I'm not sure when better using "immutable char". > > > > In C I would rather use a const pointer. But since I just started > > learing D I'm not so sure because there are so many ways. > > Don't over think it. The only thing you're doing by micro-optimization > is causing potential problems that wouldn't otherwise exist. Yeah. I don't know if I've ever seen any D code take a string*. There's really no reason to. If the string is just being passed in, then it's going to be string. If you have an array of strings, then that's what you'd pass. And if you want to mutate the string that's being passed in, then you'd pass by ref. Just about the only time that I'd expect pointers to be used with relation to strings in D is if you're calling C functions, and you need to pass a null-terminated string. - Jonathan M Davis
Re: Bug with writeln?
On Thursday, September 6, 2018 1:05:03 PM MDT Steven Schveighoffer via Digitalmars-d-learn wrote: > On 9/6/18 2:52 PM, Jonathan M Davis wrote: > > On Thursday, September 6, 2018 12:21:24 PM MDT Steven Schveighoffer via > > > > Digitalmars-d-learn wrote: > >> On 9/6/18 12:55 PM, Jonathan M Davis wrote: > >>> It's not a bug in writeln. Any time that a range is copied, you must > >>> not > >>> do _anything_ else with the original unless copying it is equivalent > >>> to > >>> calling save on it, because the semantics of copying a range are > >>> unspecified. They vary wildly depending on the range type (e.g. > >>> copying > >>> a dynamic array is equivalent to calling save, but copying a class > >>> reference is not). When you pass the range to writeln, you must > >>> assumed > >>> that it may have been consumed. And since you have range of ranges, > >>> you > >>> must assume that the ranges that are contained may have been consumed. > >>> If you want to pass them to writeln and then do anything else with > >>> them, then you'll need to call save on every range involved (which is > >>> a > >>> bit of a pain with a range of ranges, but it's necessary all the > >>> same). > >> > >> This is not necessarily true. It depends how the sub-ranges are > >> returned. > >> > >> The bug is that formattedWrite takes ranges sometimes by ref, sometimes > >> not. > >> > >> formattedWrite should call save on a forward range whenever it makes a > >> copy, and it doesn't. > >> > >> Case in point, it doesn't matter if you call writeln(b.save), the same > >> thing happens. > > > > That's still not a bug in formattedWrite. save only duplicates the > > outer-most range. And since writeln will ultimately iterate through the > > inner ranges - which weren't saved - you end up with them being > > consumed. > > That is the bug -- formattedWrite should save all the inner ranges > (writeln calls formattedWrite, and lets it do all the work). To not do > so leaves it open to problems such as consuming the sub ranges. > > I can't imagine that anyone would expect or desire the current behavior. It's exactly what you're going to get in all cases if the ranges aren't forward ranges, and it's what you have to do in general when passing ranges of ranges to functions if you want to be able to continue to use any of the ranges involved after passing them to the function. Changing formattedWrite to work around it is only a workaround for this paricular case. It's still a bug in general - though given that this would be one of the more common cases, working around it in this particular case may be worth it. It's still a workaround though and not something that can be relied on in with range-based code in general - especially when most range-based code isn't written to care about what the element types are and copies elements around all the time. > Ironically, when that bug is fixed, you *don't* have to call save on the > outer range! Except you do, because it's passed by value. If it's a dynamic array, then you're fine, since copying saves, but in the general case, you still do. > > When you're passing a range of ranges to a function, you need to > > recursively save them if you don't want the inner ranges in the > > original range to be consumed. Regardless of what formattedWrite does, > > it's a general issue with any function that you pass a range of ranges. > > It comes right back to the same issue of the semantics of copying > > ranges being unspecified and that you therefore must always use save on > > any ranges involved if you want to then use those ranges after having > > passed them to a function or copy them doing anything else. It's that > > much more annoying when you're dealing with a range of ranges rather > > than a range of something else, but the issue is the same. > It's only a problem if the subranges are returned by reference. If they > aren't, then no save is required (because they are already copies). The > fix in this case is to make a copy if possible (using save as expected). > > I think the save semantics have to be one of the worst designs in D. On that we can definitely agree. I'm strongly of the opinion that it should have been required that forward ranges be dynamic arrays or structs (no classes allowed) and that it be required that they have a postblit / copy constructor if the default copy wasn't equivalent to save. If you wanted a class that was a forward range, you would then have to wrap it in a struct with the appropriate postblit / copy constructor. That way, copying a forward range would _always_ be saving it. The harder question is what to then do with basic input ranges. Having them share code with forward ranges is often useful but also frequently a disaster, and to really be correct, they would need to either be full-on reference types or always passed around by reference. Allowing partial reference types is a total disaster when you're allowed to copy the range. Requiring that they be classes would
Re: Bug with writeln?
On Thursday, September 6, 2018 12:21:24 PM MDT Steven Schveighoffer via Digitalmars-d-learn wrote: > On 9/6/18 12:55 PM, Jonathan M Davis wrote: > > On Thursday, September 6, 2018 2:40:08 AM MDT Saurabh Das via > > Digitalmars-d-> > > learn wrote: > >> Is this a bug with writeln? > >> > >> void main() > >> { > >> > >> import std.stdio, std.range, std.algorithm; > >> > >> auto a1 = sort([1,3,5,4,2]); > >> auto a2 = sort([9,8,9]); > >> auto a3 = sort([5,4,5,4]); > >> > >> pragma(msg, typeof(a1)); > >> pragma(msg, typeof(a2)); > >> pragma(msg, typeof(a3)); > >> > >> auto b = [a1, a2, a3]; > >> pragma(msg, typeof(b)); > >> > >> writeln("b:"); > >> writeln(b); > >> writeln(b); // <-- this one prints incorrectly > >> > >> writeln("a:"); > >> writeln(a1); > >> writeln(a2); > >> writeln(a3); > >> > >> } > >> > >> Output > >> == > >> > >> SortedRange!(int[], "a < b") > >> SortedRange!(int[], "a < b") > >> SortedRange!(int[], "a < b") > >> SortedRange!(int[], "a < b")[] > >> b: > >> [[1, 2, 3, 4, 5], [8, 9, 9], [4, 4, 5, 5]] > >> [[], [], []] > >> a: > >> [1, 2, 3, 4, 5] > >> [8, 9, 9] > >> [4, 4, 5, 5] > >> > >> The issue goes away if I cast 'b' to const before writeln. I > >> think it is a bug, but maybe I am missing something? > > > > It's not a bug in writeln. Any time that a range is copied, you must not > > do _anything_ else with the original unless copying it is equivalent to > > calling save on it, because the semantics of copying a range are > > unspecified. They vary wildly depending on the range type (e.g. copying > > a dynamic array is equivalent to calling save, but copying a class > > reference is not). When you pass the range to writeln, you must assumed > > that it may have been consumed. And since you have range of ranges, you > > must assume that the ranges that are contained may have been consumed. > > If you want to pass them to writeln and then do anything else with > > them, then you'll need to call save on every range involved (which is a > > bit of a pain with a range of ranges, but it's necessary all the same). > > This is not necessarily true. It depends how the sub-ranges are returned. > > The bug is that formattedWrite takes ranges sometimes by ref, sometimes > not. > > formattedWrite should call save on a forward range whenever it makes a > copy, and it doesn't. > > Case in point, it doesn't matter if you call writeln(b.save), the same > thing happens. That's still not a bug in formattedWrite. save only duplicates the outer-most range. And since writeln will ultimately iterate through the inner ranges - which weren't saved - you end up with them being consumed. When you're passing a range of ranges to a function, you need to recursively save them if you don't want the inner ranges in the original range to be consumed. Regardless of what formattedWrite does, it's a general issue with any function that you pass a range of ranges. It comes right back to the same issue of the semantics of copying ranges being unspecified and that you therefore must always use save on any ranges involved if you want to then use those ranges after having passed them to a function or copy them doing anything else. It's that much more annoying when you're dealing with a range of ranges rather than a range of something else, but the issue is the same. - Jonathan M Davis
Re: Slicing betterC
On Thursday, September 6, 2018 11:34:18 AM MDT Adam D. Ruppe via Digitalmars-d-learn wrote: > On Thursday, 6 September 2018 at 17:10:49 UTC, Oleksii wrote: > > struct Slice(T) { > > > > size_t capacity; > > size_t size; > > T* memory; > > > > } > > There's no capacity in the slice, that is stored as part of the > GC block, which it looks up with the help of RTTI, thus the > TypeInfo reference. > > Slices *just* know their size and their memory pointer. They > don't know how they were allocated and don't know what's beyond > their bounds or how to grow their bounds. This needs to be > managed elsewhere. > > If you malloc a slice in regular D, the capacity will be returned > as 0 - the GC doesn't know anything about it. Any attempt to > append to it will allocate a whole new block. > > In -betterC, there is no GC to look up at all, and thus it has > nowhere to look. You'll have to make your own struct that stores > capacity if you need it. > > I like to do something like > > struct MyArray { >T* rawPointer; >int capacity; >int currentLength; > >// most user interaction will occur through this >T[] opSlice() { return rawPointer[0 .. currentLength]; } > >// fill in other operators as needed > } To try to make this even clearer, a dynamic array looks basically like this underneath the hood struct DynamicArray(T) { size_t length; T* ptr; } IIRC, it actually uses void* unfortunately, but that struct is basically what you get. Notice that _all_ of the information that's there is the pointer and the length. That's it. If you understand the semantics of what happens when passing that struct around, you'll understand the semantics of passing around dynamic arrays. And all of the operations that would have anything to do with memory management involve the GC - capacity, ~, ~=, etc. all require the GC. If you're not using -betterC, the fact that the dynamic array was allocated with malloc is pretty irrelevant, since all of those operations will function exactly the same as if the dynamic array were allocated by the GC. It's just that because the dynamic array is not GC-allocated, it's guaranteed that the capacity is 0, and therefore any operations that would increase the arrays length then require reallocating the dynamic array with the GC, whereas if it were already GC-allocated, then its capacity might have been greater than its length, in which case, reallocation would not be required. If you haven't read it already, I would suggest reading this article: https://dlang.org/articles/d-array-article.html It does not use the official terminology, but in spite of that, it should really help clarify things for you. The article refers to T[] as being a slice (which is accurate, since it is a slice of memory), but it incorrectly refers to the memory buffer itself as being the dynamic array, whereas the language spec considers the T[] (the struct shown above) to be the dynamic array. The language does not have a specific name for that memory buffer, and it considers a T[] to be dynamic array regardless of what memory it refers to. So, you should keep that in mind when reading the article, but the concepts that it teaches are very much correct and should help a great deal in understanding how dynamic arrays work in D. - Jonathan M Davis
Re: Bug with writeln?
On Thursday, September 6, 2018 2:40:08 AM MDT Saurabh Das via Digitalmars-d- learn wrote: > Is this a bug with writeln? > > void main() > { > import std.stdio, std.range, std.algorithm; > > auto a1 = sort([1,3,5,4,2]); > auto a2 = sort([9,8,9]); > auto a3 = sort([5,4,5,4]); > > pragma(msg, typeof(a1)); > pragma(msg, typeof(a2)); > pragma(msg, typeof(a3)); > > auto b = [a1, a2, a3]; > pragma(msg, typeof(b)); > > writeln("b:"); > writeln(b); > writeln(b); // <-- this one prints incorrectly > > writeln("a:"); > writeln(a1); > writeln(a2); > writeln(a3); > > } > > Output > == > > SortedRange!(int[], "a < b") > SortedRange!(int[], "a < b") > SortedRange!(int[], "a < b") > SortedRange!(int[], "a < b")[] > b: > [[1, 2, 3, 4, 5], [8, 9, 9], [4, 4, 5, 5]] > [[], [], []] > a: > [1, 2, 3, 4, 5] > [8, 9, 9] > [4, 4, 5, 5] > > The issue goes away if I cast 'b' to const before writeln. I > think it is a bug, but maybe I am missing something? It's not a bug in writeln. Any time that a range is copied, you must not do _anything_ else with the original unless copying it is equivalent to calling save on it, because the semantics of copying a range are unspecified. They vary wildly depending on the range type (e.g. copying a dynamic array is equivalent to calling save, but copying a class reference is not). When you pass the range to writeln, you must assumed that it may have been consumed. And since you have range of ranges, you must assume that the ranges that are contained may have been consumed. If you want to pass them to writeln and then do anything else with them, then you'll need to call save on every range involved (which is a bit of a pain with a range of ranges, but it's necessary all the same). In many cases, you can get away with passing a range to a function or use it with foreach and then continue to use it after that, but that's only because copying those ranges is equivalent to calling save on them. It doesn't work if any of the ranges involved aren't saved when they're copied, and it doesn't work in generic code, because you have no clue whether the ranges that are going to be used with that code are going to be saved when they're copied. - Jonathan M Davis
Re: Function parameter type inference: is this example working as intended?
On Tuesday, September 4, 2018 8:33:47 PM MDT Nathan S. via Digitalmars-d- learn wrote: > The below writes "uint". Is this working as intended? > https://run.dlang.io/is/Dx2e7f > > --- > import std.stdio; > > auto foo(T = uint)(uint x) > { > return T.stringof; > } > > auto foo(T = ulong)(ulong x) > { > return T.stringof; > } > > void main() > { > writeln(foo(10L)); > } > --- Probably, though personally, I'm inclined to think that it should pick the second. It's clearly using VRP to decide that 10L fits in a uint. If you pick something like writeln(foo(99L)); then it will call the ulong overload. Either way, since a long is neither a uint or a ulong, it has to pick which overload it thinks is better. It would seem to me that ulong would be closer (and if VRP weren't involved, it would pick the ulong overload), but given that it knows what the value is, it knows that either can work. Unfortunately, searching through the spec, I don't see anything in it mentioning either VRP or Value Range Propagation, so it doesn't look like the correct behavior is actually spec-ed out. It could be that it works the way it does in this case because of an intentional choice, or it could just be the consequence of logic choices that make sense in other contexts but not so much here. Personally, I would argue that VRP shouldn't come into play if it's not necessary, but I don't know what the actual rules for it are. I suggest that you report this as a potential bug. At minimum, the spec needs to be updated with the rules for VRP. - Jonathan M Davis
Re: Mutable ForwardRange save() method not callable using const object
On Tuesday, September 4, 2018 9:22:26 AM MDT Timoses via Digitalmars-d-learn wrote: > On Tuesday, 4 September 2018 at 14:26:44 UTC, Steven > > Schveighoffer wrote: > > [...] > > As general advice, I wouldn't expect const to work well with > > Ranges anyway -- const ranges are useless (you can't iterate > > them). So not much code is expecting to handle const, including > > the wrappers that Phobos provides. > > Thanks, that sounds like some good advice. I've actually bumped > into this right after when I had an immutable range which was > supposed to fill in its cache when being iterated. > My argument for why this should work is that "from the outside of > the range" it is immutable, since accessing via opIndex will > always give the same value. > ... In the end, that'll lead nowhere. The immutable attribute > would become a "promise" rather than an enforcement (or too hard > for the compiler to enforce). That's simply not how const or immutable work in D though. They're actual compiler guarantees, and it's undefined behavior to ever cast away const or immutable and mutate the object. D's const is fundamentally different from C++'s const in this regard. Not only is a const that doesn't provide compiler guarantees useless according to Walter (though that's obviously debatable), but the nature of immutable pretty much requires it. immutable objects are implicitly shared, and in principle, they could end up in ROM. So, even if your object is const, there's no guarantee that it's actually mutable underneath the hood. The rigidness of D's const and immutable are both a blessing and a curse. But the net result is we really can't have a range API that works with them without more of a head/tail model (whereas the current API mutates in place), and even if we had a head/tail model, it would still get pretty hairy thanks to issues like reference counting. So, as Steven points out, const and ranges don't go together at all. The result is that a number of us use stuff like const and inout pretty sparingly (at least outside of primitive types): http://jmdavisprog.com/articles/why-const-sucks.html - Jonathan M Davis
Re: Can passing an address of this to a non-copyable object be made trusted? - i.e. can I disable moving?
On Sunday, August 26, 2018 5:10:29 PM MDT Nicholas Wilson via Digitalmars-d- learn wrote: > On Sunday, 26 August 2018 at 20:17:30 UTC, aliak wrote: > > So if we had this: > > > > struct A(T) { > > > > auto proxy() @trusted { > > > > return B!T(); > > > > } > > > > } > > > > struct B(T) { > > > > private A!T* source; > > private this(A!T* s) { source = s; } > > @disable this(); > > @disable this(this) {} > > @disable void opAssign(B!T); > > > > } > > > > In order for f to be "safe" I need to ensure that B!T() > > does not escape the scope of A!T. I figured disable > > construction and copying may work, but it seems you can still > > get it moved: > > > > void main() @safe { > > > > auto f() { > > > > auto a = A!int(); > > return a.proxy; > > > > } > > auto escaped = f; // escaped.source is gone... > > > > } > > > > Anyway around this? > > > > Cheers, > > - Ali > > Not sure abut the current language but DIP1014 > https://github.com/dlang/DIPs/blob/master/DIPs/DIP1014.md#final-review > > "The point was made that allowing opPostMove to be overidden > raises the question of what to do when it is annotated with > @disable. The concensus was that, in such a case, an actual > attempt to move the object would result in a compilation error." > > So, soon™? Yeah. Hopefully, we're able to disable moving at some point in the near future. However, right now, it's definitely not possible. So, if you have a type where it won't work properly if it's ever moved, then either you need to rethink what you're doing, or you must be _very_ careful with how you use any object of that type so that you don't ever use it in a way that even might result in it being moved. - Jonathan M Davis
Re: Clock.currTime differs from SysTime
On Saturday, August 25, 2018 6:53:24 AM MDT Ivo via Digitalmars-d-learn wrote: > I am using Clock.currTime.stdTime to get a unique timestamp in my > program. > Now I need to produce something similar in a different > programming language; so I'm trying to understand how > Clock.currTime works. > > According the the documentation Clock.currTime.stdTime should > return the number of hnseconds since 00:00 of 01/01/0001 A.D. > UTC. However it seems that it returns less than what claimed. > > Consider the following code: > > import std.stdio; > import std.datetime.date : DateTime; > import std.datetime.timezone : UTC; > import std.datetime.systime; > > void main() { > > auto now = Clock.currTime; > auto date = DateTime(2018, 8, 25, 14, 42, 0); //this is changed > manually > auto st = SysTime(date, UTC()); > writeln(st.stdTime); > writeln(st.toISOExtString); > writeln(now.stdTime); > writeln(now.toISOExtString); > > } > > I'm done a few tries and here is an output: > 6367080492 //this is st.stdTime > 2018-08-25T14:42:00Z > 636707977205129550 //this is now.stdTime > 2018-08-25T14:42:00.512955 > > So here is the problem: the difference in time is less than 0.6 > seconds (according to the strings), nevertheless the difference > of the 2 numbers is 71994870450. > 71994870450 hnsecs = 71994870450 x 10^{-7} secs = 7199,487045 > secs (unless my maths is wrong) > > So what actually is Clock.currTime.stdTime counting? By default, Clock.currTime returns a SysTime with LocalTime as the TimeZone. stdTime is always in UTC. So, now's TimeZone is LocalTime, and when you print it out as a string, you get the date and time in your local time zone (which you can tell by the lack of time zone information on the end of the string), whereas when you then construct a SysTime using the same date and time as your local time zone but tell it that it's in UTC, then the two values are going to be off by the offset between your local time zone and UTC - and of course, casting to DateTime strips off the fractional seconds. If you want to cast a SysTime to DateTime and then construct a SysTime from it again, then you need to construct the SysTime with the same TimeZone, or they won't be the same. And sadly, even if you _do_ do that, and the time was right on the second (so that there are no fractional seconds), they _still_ might not be the same if the date and time are near a DST switch. Even though it _usually_ works to convert between a time zone and UTC, in the general case, it's impossible - with some DST switches you get times that are completely skipped and thus technically aren't valid, whereas at other DST switches, you have times that happen twice, resulting in ambiguity. That's why SysTime always holds the time internally in UTC rather than in whatever time zone it's set to. The TimeZone object is just used when a function on SysTime requires that it be converted out of UTC (e.g. when printing out a string or using a property like year). Unfortunately, that still leaves a problem of what to do when constructing a SysTime from date and time during a DST switch, and SysTime does it's best, but unfortunately, trying to convert from a time zone to UTC is inherently a buggy process. In this particular case, DST almost certainly was not a factor, but you still ran into problems, because you used a different time zone when constructing the new object. So, while it's certainly sometimes necessary to construct a SysTime from a DateTime (or separate numbers), it's almost always better to leave the result of Clock.currTime as a SysTime rather than doing something like casting to DateTime and then constructing another SysTime from it. Done "correctly," it will work most of the time, but you'll still be screwed around DST switches. - Jonathan M Davis