Re: How do you peek a variant containing a complex value?
On Saturday, 22 February 2020 at 18:32:06 UTC, nullptr wrote: The type in v isn't Complex, it's Complex!double. Ah, great. Thanks! Missed that.
How do you peek a variant containing a complex value?
The following program won't compile if I uncomment the if statement: void main() { Variant v = complex(1.0, 1.0); //if (v.peek!(Complex)) { //writeln("Complex"); //} writeln(v); } I get the same error with v.peek!(complex), which is: Error: template instance peek!(Complex) does not match template declaration peek(T)() The variant can clearly hold a complex value. Someone please tell me - what am I doing wrong in the peek call?
Re: How does one cast to an array type?
On Thursday, 17 October 2019 at 12:40:33 UTC, Adam D. Ruppe wrote: On Thursday, 17 October 2019 at 12:19:03 UTC, Vinay Sajip wrote: Are arrays and objects part of a unified type system? No, they are separate. You can define a class that contains an array, but it doesn't work like that automatically. You'll want to use a wrapper class or a variant type or a template or something for this depending on your exact use case. The use case is that I have a specialised comparator function that takes any two objects, including potentially array of objects, and processes things accordingly. Perhaps a Variant will be the best bet, as the decision as to how to process has to be made at run time rather than compile time, and effectively based on user inputs. Thanks for the suggestions, Vinay Sajip
How does one cast to an array type?
Are arrays and objects part of a unified type system? Specifically, if I do void foo(Object x) { if (typeid(x) == typeid(Object[])) { auto a = cast(Object[]) x; } } I get a compilation error: onlineapp.d(3): Error: cannot cast expression x of type object.Object to Object[] What's the way to achieve the cast, which should be safe given the typeid check? Thanks and regards, Vinay Sajip
Re: Fields with the same name not causing a warning?
On Friday, 16 November 2018 at 19:12:42 UTC, Dennis wrote: If something is definitively wrong, then it should be an error. If it's not definitively wrong, then the compiler shouldn't say anything about it, and it should be left up to a linter tool of some kind like dcd." https://forum.dlang.org/post/mailman.3986.1537881312.29801.digitalmar...@puremagic.com Thanks for that link, it helps to understand the thinking behind the way things are. The language design could be fixed by requiring the use of the `override` keyword like in C#. However, in D it *might* make generic code (with mixins) more complicated, though I personally have never found a use for hiding member variables so I don't know the rationale. More complicated for the compiler writers, or users of mixins/generics? In any case, the example I showed was more commonplace than mixins and templates. Perhaps the default should be to fail compilation with an error, and allow `override` when someone actually wants to hide/shadow members in base classes, for whatever reason. I suggested "warning" rather than "error" in the OP, because I didn't know the philosophy behind warnings in D that you've now made me aware of. But presumably making it an error would potentially be a breaking change?
Re: Fields with the same name not causing a warning?
On Friday, 16 November 2018 at 17:35:13 UTC, Basile B. wrote: D is not a compiler that warns much. You can still open an issue asking for this (and the warning must be easy to add at first glance), but the policy applied to warnings is "compilers warnings are a sign of design flaws so instead of emitting one we should rather fix the flaw". Design flaws in what? In this case, the flaw was in my code, but I would expect some help from the compiler in catching such an ambiguity, and so fixing the flaw in my code. That it didn't try to help me might itself be considered a design flaw in the compiler ;-)
Re: Fields with the same name not causing a warning?
On Friday, 16 November 2018 at 17:08:00 UTC, Basile B. wrote: I agree that this is almost a case of shadowing but i don't know the exact rationale for allowing this. I'm not saying it shouldn't be allowed - just that the compiler could warn you about what might very well be a mistake (as it was in my case) - hard to debug with printf debugging, and source level debug for D is a bit thin on the ground, ISTM.
Fields with the same name not causing a warning?
This code should IMO give at least a warning, but it doesn't: abstract class A { int kind; } class B : A { int kind; this(int k) { kind = k; } } In my actual code, the declaration of field "kind" in B was left in accidentally. Surprisingly, however, no warning was emitted when I compiled this, leading to B having two fields called kind which are distinct from one another. The complete program import std.stdio; abstract class A { int kind; } class B : A { int kind; this(int k) { kind = k; } } void main() { auto b = new B(4); A a = b; writeln(b.kind); writeln(a.kind); } prints 4 0 Given that this is the kind of thing that is easily done, surely the default behaviour should be for the compiler to emit at least a warning that field "kind" is ambiguous in B? This behaviour occurs even when the field is declared as "public" or "protected" in both classes. What am I missing?
Re: Using decodeFront with a generalised input range
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?
Re: Using decodeFront with a generalised input range
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! 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.
Using decodeFront with a generalised input range
According to the std.utf documentation, decode will only work with strings and random access ranges of code units with length and slicing, whereas decodeFront will work with any input range of code units. However, I can't seem to get such a usage to compile: the following code import std.range; import std.utf; void somefn(InputRange!(ubyte) r) { r.decodeFront!(No.useReplacementDchar, dchar)(); } gives a compilation error: onlineapp.d(5): Error: template std.utf.decodeFront cannot deduce function from argument types !(cast(Flag)false, dchar)(InputRange!ubyte), candidates are: /dlang/dmd/linux/bin64/../../src/phobos/std/utf.d(1176): std.utf.decodeFront(Flag useReplacementDchar = No.useReplacementDchar, S)(ref S str, out size_t numCodeUnits) if (!isSomeString!S && isInputRange!S && isSomeChar!(ElementType!S)) /dlang/dmd/linux/bin64/../../src/phobos/std/utf.d(1214): std.utf.decodeFront(Flag useReplacementDchar = No.useReplacementDchar, S)(ref S str, out size_t numCodeUnits) if (isSomeString!S) /dlang/dmd/linux/bin64/../../src/phobos/std/utf.d(1243): std.utf.decodeFront(Flag useReplacementDchar = No.useReplacementDchar, S)(ref S str) if (isInputRange!S && isSomeChar!(ElementType!S)) I'm not sure what's wrong here. Also, the information in the error message seems to indicate that decodeFront isn't expecting to work on a generic InputRange interface, but rather a subset which comes from an actual string. Have I read that wrong? I get the same error with leaving out the useReplacementDchar flag, i.e. `r.decodeFront!(dchar)()`
Re: Creating InputRanges from strings, files etc.
On Thursday, 8 November 2018 at 16:41:50 UTC, Steven Schveighoffer wrote: I did this in a run.dlang.org playground: pragma(msg, ElementType!(typeof(b))); pragma(msg, ElementType!(typeof(d))); I get: immutable(ubyte) ubyte Which means they aren't the same type, and they don't define the same interface (InputRange!(ubyte) is not the same as InputRange!(immutable(ubyte)) ). Other than simply using compile-time functions, and dropping the object interface as Alex suggests, the easiest thing I can recommend is wrapping representation into a casting input range such as map: auto b = inputRangeObject(a.representation.map!(b => ubyte(b))); You can see all this here: https://run.dlang.io/is/1E6Uqj -Steve Thanks, guys, those are helpful pointers.
Re: Creating InputRanges from strings, files etc.
On Thursday, 8 November 2018 at 14:38:37 UTC, Paul Backus wrote: To pass these ranges around using the `InputRange` interface, use `inputRangeObject` to wrap them: InputRange!ubyte r3 = inputRangeObject(r1); InputRange!(immutable(ubyte)) r4 = inputRangeObject(r2); I did a bit more digging, and it seems to work for strings but not for files: The program import std.algorithm.iteration; import std.format; import std.range; import std.stdio; import std.string; void somefn(InputRange!(immutable(ubyte)) r) { writeln(format!"%s"(r)); } void main() { auto a = "Hello, world!"; auto b = inputRangeObject(a.representation); somefn(b); auto c = stdin.byChunk(1024).joiner; auto d = inputRangeObject(c); //somefn(d); } compiles as given above, but if the somefn(d) line is uncommented, I get an error: function onlineapp.somefn(InputRange!(immutable(ubyte)) r) is not callable using argument types (InputRangeObject!(Result)) onlineapp.d(18):cannot pass argument d of type std.range.interfaces.InputRangeObject!(Result) to parameter InputRange!(immutable(ubyte)) r Do I need to do an explicit cast? If so, can someone tell me the precise incantation? How come it doesn't figure out that the underlying range is a ubyte range, or is it to do with immutability, or something else altogether?
Re: Creating InputRanges from strings, files etc.
On Thursday, 8 November 2018 at 14:38:37 UTC, Paul Backus wrote: You can iterate through a file one ubyte at a time using `byChunk` and `joiner`: auto r1 = stdin.byChunk(1024).joiner; assert(is(typeof(r1.front) == ubyte)); You can iterate through a string one ubyte at a time using `representation`: auto r2 = "To be or not to be".representation; assert(is(typeof(r2.front) == immutable(ubyte))); To pass these ranges around using the `InputRange` interface, use `inputRangeObject` to wrap them: InputRange!ubyte r3 = inputRangeObject(r1); InputRange!(immutable(ubyte)) r4 = inputRangeObject(r2); Aha - inputRangeObject was the thing I was missing. Thanks!
Creating InputRanges from strings, files etc.
Excuse my ignorance, but from looking at the documentation on std.range and a quick skim of the guides mentioned there near the top, I can't see what the simple way is of creating an InputRange!(ubyte) from strings, files etc. I would have expected to find something in the DLang Tour about this, but couldn't find anything. Please can someone tell me how to do it? Just to be clear, I want to create an object which is an InputRange!(ubyte) and pass that around, rather than e.g. iterate over a string or a file.
Re: Reading binary streams with decoding to Unicode
On Monday, 15 October 2018 at 22:49:31 UTC, Nicholas Wilson wrote: Oh, sorry I missed that. Take a look at https://github.com/schveiguy/iopipe Great, thanks.
Re: Reading binary streams with decoding to Unicode
On Monday, 15 October 2018 at 19:56:22 UTC, Nicholas Wilson wrote: import std.file : readText; import std.uni : byCodePoint, byGrapheme; // or import std.utf : byCodeUnit, byChar /*utf8*/, byWchar /*utf16*/, byDchar /*utf32*/, byUTF /*utf8(?)*/; string a = readText("foo"); foreach(cp; a.byCodePoint) { // do stuff with code point 'cp' } Your example shows reading an entire file into memory (string a = readText("foo")), then iterating over that. I know you can iterate over a string; I'm interested in iterating over a stream, which is perhaps read over a network or from another I/O source, where you can't assume you have access to all of it at once - just one Unicode character at a time.
Re: Reading binary streams with decoding to Unicode
On Monday, 15 October 2018 at 17:55:34 UTC, Dukc wrote: This is done automatically for character arrays, which includes strings. wchar arrays wil iterate by UTF-16, and dchar arrays by UTF-32. If you have a byte/ubyte array you know to be unicode-encoded, convert it to char[] to iterate by code points. Thanks for the response. I was looking for something where I don't have to manage buffers myself (e.g. when handling buffered file or socket I/O). It's really easy to find this functionality in e.g. Python, C#, Go, Kotlin, Java etc. but I'm surprised there doesn't seem to be a ready-to-go equivalent in D. For example, I can find D examples of opening files and reading a line at a time, but no examples of opening a file and reading Unicode chars one at a time. Perhaps I've just missed them?
Reading binary streams with decoding to Unicode
Is there a standardised way of reading over buffered binary streams (at least strings, files, and sockets) where you can layer a decoder on top, so you get a character stream you can read one Unicode char at a time? Initially UTF-8, but later also other encodings. I see that std.stream was deprecated, but can't see what other options there are. Can anyone point me in the right direction?