Re: Why does this code only work with `std.conv.to` whilst not with `cast`?
On Sunday, 8 January 2023 at 12:39:37 UTC, thebluepandabear wrote: ... The `foreach` worked for that case since `bark` is a method of `IDog`. `update` is not so a conversion to `Button[]` is needed. In that case, you could do a casting like this: import std.stdio, std.conv; interface IDog { void bark(); } class Dog: IDog{ string s; this(string _s){s = _s;} void bark(){writeln(s);} void update(string _s){ s ~= " - " ~ _s; } } class List{ IDog[] dogs; void add(T)(T d){ dogs ~= d; } } void main(){ auto d1 = new Dog("meaw!"); auto d2 = new Dog("wof!"); auto l = new List(); l.add(d1); l.add(d2); foreach(i,d; l.dogs){ // I'm using 'i' just to show each update. (cast(Dog)d).update(to!string(i)); d.bark(); } } Prints: meaw! - 0 wof! - 1 Matheus.
Re: Why does this code only work with `std.conv.to` whilst not with `cast`?
On Sunday, 8 January 2023 at 11:29:10 UTC, thebluepandabear wrote: ... There is an explanation here: https://forum.dlang.org/post/tqukutfzeaxedunuv...@forum.dlang.org But in any case I'd like to point it out that I think you could do that foreach without casting or std.conv by just omitting the type of the variable you're iterating: import std.stdio, std.conv; interface IDog { void bark(); } class Dog: IDog{ string s; this(string _s){s = _s;} void bark(){writeln(s);} } class List{ IDog[] dogs; void add(T)(T d){ dogs ~= d; } } void main(){ auto d1 = new Dog("meaw!"); auto d2 = new Dog("wof!"); auto l = new List(); l.add(d1); l.add(d2); foreach(d; l.dogs){ // No type informed for "d" d.bark(); } } Prints: meaw! wof! Matheus.
Re: Why does this code only work with `std.conv.to` whilst not with `cast`?
On Sunday, 8 January 2023 at 12:35:38 UTC, matheus wrote: On Sunday, 8 January 2023 at 11:29:10 UTC, thebluepandabear wrote: ... There is an explanation here: https://forum.dlang.org/post/tqukutfzeaxedunuv...@forum.dlang.org But in any case I'd like to point it out that I think you could do that foreach without casting or std.conv by just omitting the type of the variable you're iterating: import std.stdio, std.conv; interface IDog { void bark(); } class Dog: IDog{ string s; this(string _s){s = _s;} void bark(){writeln(s);} } class List{ IDog[] dogs; void add(T)(T d){ dogs ~= d; } } void main(){ auto d1 = new Dog("meaw!"); auto d2 = new Dog("wof!"); auto l = new List(); l.add(d1); l.add(d2); foreach(d; l.dogs){ // No type informed for "d" d.bark(); } } Prints: meaw! wof! Matheus. The `foreach` worked for that case since `bark` is a method of `IDog`. `update` is not so a conversion to `Button[]` is needed. I will look at your resource, thanks.
Re: Why does this code only work with `std.conv.to` whilst not with `cast`?
On 08.01.23 12:29, thebluepandabear wrote: ```D interface ICustomDrawable { void render(sfRenderWindow* renderWindow); } [...]> class Button : ICustomDrawable { [...] } [...] class StackLayout : ICustomDrawable { [...] ICustomDrawable[] _children; } ``` For some reason, when I want to cast the `children` (property), only the second example works: 1. ```D foreach (Button button; cast(Button[])(_boardSizeRow.children)) { button.update(event, _renderWindow); } ``` 2. ```D foreach (Button button; to!(Button[])(_boardSizeRow.children)) { button.update(event, _renderWindow); } ``` Two things you need to know: 1. While an interface reference implicitly converts to a compatible class reference, the resulting pointer is slightly different. interface I {} class C : I {} void main() { C c = new C; I i = c; import std.stdio; writeln(cast(void*) c); /* e.g. 7F3C140A7000 */ writeln(cast(void*) i); /* e.g. 7F3C140A7010 */ } 2. Casting from one array type to another is done "as a type paint"[1]. The elements of the array are reinterpreted, not converted. But reinterpreting interface references as class references won't work, because the pointers will be wrong. You need to convert each element of the array (which is what `to` does). [1] https://dlang.org/spec/expression.html#cast_array
Why does this code only work with `std.conv.to` whilst not with `cast`?
I've been writing some code and I have been experimenting with casting. I've found that sometimes only `std.conv.to!` does the job over casting, and I am unsure why this is the case as I assumed that they are both the same. I have the following interface: ```D interface ICustomDrawable { void render(sfRenderWindow* renderWindow); } ``` And the following class that implements that interface: ```D class Button : ICustomDrawable { ... override void render(sfRenderWindow* renderWindow) { ... } } ``` And this class which uses `ICustomDrawable`: ```D class StackLayout : ICustomDrawable { ... void addChild(T)(T child) { static assert(is(T : ICustomDrawable), "Invalid type T for child"); ... } ... ICustomDrawable[] _children; } ``` For some reason, when I want to cast the `children` (property), only the second example works: 1. ```D foreach (Button button; cast(Button[])(_boardSizeRow.children)) { button.update(event, _renderWindow); } ``` 2. ```D foreach (Button button; to!(Button[])(_boardSizeRow.children)) { button.update(event, _renderWindow); } ``` When I run the first code example I get a black screen, whilst with the second I do not. I find this very strange as when I write to the console the 'type', it is the same for both scenarios. Help would be appreciated as to why this is happening so I can better understand how D works.
Re: std.conv.to
On 6/17/22 8:48 AM, harakim wrote: On Friday, 17 June 2022 at 12:31:45 UTC, harakim wrote: I can generically convert a string to a type using to!type. I have a read function that does that. I have simplified the example below: ```d int readNumber() { return read!int(val => to!int(val), "number"); } string readTime() { return read!string(val => toTime(val), "time"); } private T read(T)(T function(string) transform, string typeName) { string input = readln(); return transform(input); } ``` However, I want to be able to convert my own custom types as well. How do I do that? Is there an operator overload I need to override for that? Do I have to static if on the template type and call the object? I have no idea why I was stuck on this problem for so long. I can specify anything I want in the transform and I even do in my own example lol. I am still curious if there is a way to make your type work with to!MyCustomType(source) `to` uses natural hints that it can find via introspection. As others have pointed out, you can define a constructor in the target type to take the source type. To go the other way, you can define an `opCast` in the source type (if that's possible). If you want to convert to string (a specialized case), use a `toString` member function. For class to class conversion, `to` will try a dynamic cast if none of the above is the case. I believe there is no specific hook aside from these that allows you to define a conversion path. -Steve
Re: std.conv.to
On Friday, 17 June 2022 at 18:40:59 UTC, Ali Çehreli wrote: On 6/17/22 10:04, Salih Dincer wrote: > Isn't foo and bar the same thing? I don't understand what's the > difference! > ```d >auto foo = to!Foo("123"); //?? >auto bar = Foo("321"); > ``` Yes, they are the same thing. But (!) `to!` inconsiderately smuggled into the code is bubble. So we will obviously be deceived at a later moment. Thereby making nonsense further clamour for shorten...:) Then how did the evolution of the code evolve into the current form? ```d auto zar = "123".to!Foo; auto bar = to!(Foo)("123"); auto foo = to!Foo("123"); // <-- this line is bubble ``` SDB@79
Re: std.conv.to
On 6/17/22 10:04, Salih Dincer wrote: > Isn't foo and bar the same thing? I don't understand what's the > difference! >auto foo = to!Foo("123"); //?? >auto bar = Foo("321"); Yes, they are the same thing. The OP was looking for a generic way of converting any type to any other type as long as there is a way. (Think a function template.) std.conv.to can do that because it considers the constructors as well. Ali
Re: std.conv.to
On Friday, 17 June 2022 at 12:53:53 UTC, bauss wrote: Just add a constructor to your type that takes the value of what you want to convert. Working example: ```d struct Foo { int value; this(int v) { value = v; } this(string v) { this(to!int(v)); } } void main() { auto foo = to!Foo("123"); writeln(foo.value); } ``` D is full of good surprises. Thanks.
Re: std.conv.to
On Friday, 17 June 2022 at 12:53:53 UTC, bauss wrote: Just add a constructor to your type that takes the value of what you want to convert. Isn't foo and bar the same thing? I don't understand what's the difference! By the way, what's the question? Is this the answer to the question? ```d void main() { auto foo = to!Foo("123"); //?? typeid(foo).writeln(": ", foo); assert("123".to!Foo == foo); assert(123.to!Foo == foo); auto bar = Foo("321"); typeid(bar).writeln(": ", bar); assert("321".to!Foo == bar); assert(321.to!Foo == bar); } ``` SDB@79
Re: std.conv.to
On Friday, 17 June 2022 at 12:48:56 UTC, harakim wrote: On Friday, 17 June 2022 at 12:31:45 UTC, harakim wrote: I can generically convert a string to a type using to!type. I have a read function that does that. I have simplified the example below: ```d int readNumber() { return read!int(val => to!int(val), "number"); } string readTime() { return read!string(val => toTime(val), "time"); } private T read(T)(T function(string) transform, string typeName) { string input = readln(); return transform(input); } ``` However, I want to be able to convert my own custom types as well. How do I do that? Is there an operator overload I need to override for that? Do I have to static if on the template type and call the object? I have no idea why I was stuck on this problem for so long. I can specify anything I want in the transform and I even do in my own example lol. I am still curious if there is a way to make your type work with to!MyCustomType(source) Just add a constructor to your type that takes the value of what you want to convert. Working example: ```d struct Foo { int value; this(int v) { value = v; } this(string v) { this(to!int(v)); } } void main() { auto foo = to!Foo("123"); writeln(foo.value); } ```
Re: std.conv.to
On Friday, 17 June 2022 at 12:31:45 UTC, harakim wrote: I can generically convert a string to a type using to!type. I have a read function that does that. I have simplified the example below: ```d int readNumber() { return read!int(val => to!int(val), "number"); } string readTime() { return read!string(val => toTime(val), "time"); } private T read(T)(T function(string) transform, string typeName) { string input = readln(); return transform(input); } ``` However, I want to be able to convert my own custom types as well. How do I do that? Is there an operator overload I need to override for that? Do I have to static if on the template type and call the object? I have no idea why I was stuck on this problem for so long. I can specify anything I want in the transform and I even do in my own example lol. I am still curious if there is a way to make your type work with to!MyCustomType(source)
std.conv.to
I can generically convert a string to a type using to!type. I have a read function that does that. I have simplified the example below: ```d int readNumber() { return read!int(val => to!int(val), "number"); } string readTime() { return read!string(val => toTime(val), "time"); } private T read(T)(T function(string) transform, string typeName) { string input = readln(); return transform(input); } ``` However, I want to be able to convert my own custom types as well. How do I do that? Is there an operator overload I need to override for that? Do I have to static if on the template type and call the object?
Re: Unexpected result with std.conv.to
On Friday, 15 November 2019 at 04:26:58 UTC, Jon Degenhardt wrote: On Friday, 15 November 2019 at 03:51:04 UTC, Joel wrote: I made a feature that converts, say, [9:59am] -> [10:00am] to 1 minute. but found '9'.to!int = 57 (not 9). Doesn't seem right... I'm guessing that's standard though, same with ldc. Use a string or char[] array. e.g. writeln("9".to!int) => 9. With a single 'char' what is being produced is the ascii value of the character. Thanks, Jon Degenhardt. I did work it out.
Re: Unexpected result with std.conv.to
On Friday, 15 November 2019 at 03:51:04 UTC, Joel wrote: I made a feature that converts, say, [9:59am] -> [10:00am] to 1 minute. but found '9'.to!int = 57 (not 9). Doesn't seem right... I'm guessing that's standard though, same with ldc. Use a string or char[] array. e.g. writeln("9".to!int) => 9. With a single 'char' what is being produced is the ascii value of the character.
Unexpected result with std.conv.to
I made a feature that converts, say, [9:59am] -> [10:00am] to 1 minute. but found '9'.to!int = 57 (not 9). Doesn't seem right... I'm guessing that's standard though, same with ldc.
Re: tryTo: non-throwing variant of std.conv.to
On Wednesday, 15 August 2018 at 10:38:23 UTC, Jonathan M Davis wrote: Would it be sane to add these to std.conv alongside existing std.conv.to so that underlying logic in std.conv.to can be reused? If so, AFAICT, existing std.conv.to should be implemented on Put something together to get early feedback on the idea: https://github.com/dlang/phobos/pull/6665
Re: tryTo: non-throwing variant of std.conv.to
On Wednesday, 15 August 2018 at 09:26:26 UTC, Seb wrote: If so, AFAICT, existing std.conv.to should be implemented on top of std.conv.tryTo. Well, for now you can use `ifThrown` from std.exception: https://dlang.org/phobos/std_exception.html#ifThrown --- "foo".to!int.ifThrown(42) But the whole idea is to avoid both throwing and catching exceptions at all. As this results in orders of magnitudes of drop in performance for the throwing case. That's the reason why Folly has this aswell. Thanks anyway, Seb.
Re: tryTo: non-throwing variant of std.conv.to
On Wednesday, August 15, 2018 3:21:29 AM MDT Per Nordlöw via Digitalmars-d- learn wrote: > Have anybody thought about non-throwing variants of std.conv.to > typically named `tryTo` > similar to what Folly > > https://github.com/facebook/folly/blob/master/folly/docs/Conv.md#non-throw > ing-interfaces > > does, for instance, as > > tryTo(str).then([](int i) { use(i); }); > > ? > > Would it be sane to add these to std.conv alongside existing > std.conv.to so that underlying logic in std.conv.to can be reused? > > If so, AFAICT, existing std.conv.to should be implemented on top > of std.conv.tryTo. Yes. I've considered writing a set of conversion functions like std.conv.to which return a Nullable!T (where the target type is T) and return Nullable!T.init when the conversion fails rather than throwing, and they really should be in std.conv alongside to, reusing logic as much as reasonably possible, but it's not a small project. It's come up off and on for a while now, so I expect that someone will do it eventually (and I may at some point if no one else does), but obviously, someone has to actually take the time to do it, or it's not going to happen. - Jonathan M Davis
Re: tryTo: non-throwing variant of std.conv.to
On Wednesday, 15 August 2018 at 09:21:29 UTC, Per Nordlöw wrote: Have anybody thought about non-throwing variants of std.conv.to typically named `tryTo` similar to what Folly https://github.com/facebook/folly/blob/master/folly/docs/Conv.md#non-throwing-interfaces does, for instance, as tryTo(str).then([](int i) { use(i); }); ? Would it be sane to add these to std.conv alongside existing std.conv.to so that underlying logic in std.conv.to can be reused? If so, AFAICT, existing std.conv.to should be implemented on top of std.conv.tryTo. Well, for now you can use `ifThrown` from std.exception: https://dlang.org/phobos/std_exception.html#ifThrown --- "foo".to!int.ifThrown(42) --- https://run.dlang.io/is/nlZKOw Usage of optionals/nullables is sadly not very common in Phobos and I think if we want everything to work nicely, we probably have to start a new standard library (or do massive refactorings of the existing one.)
tryTo: non-throwing variant of std.conv.to
Have anybody thought about non-throwing variants of std.conv.to typically named `tryTo` similar to what Folly https://github.com/facebook/folly/blob/master/folly/docs/Conv.md#non-throwing-interfaces does, for instance, as tryTo(str).then([](int i) { use(i); }); ? Would it be sane to add these to std.conv alongside existing std.conv.to so that underlying logic in std.conv.to can be reused? If so, AFAICT, existing std.conv.to should be implemented on top of std.conv.tryTo.
Re: Nothrow std.conv.to with explicit default value
On Wednesday, 20 June 2018 at 14:39:48 UTC, Per Nordlöw wrote: Is there a way to avoid compile-time-string-concat plus mixin here? Using __traits(getMember, ...) should compile faster, right? T toDefaulted(T)(scope const(char)[] value, T defaultValue) @safe pure nothrow @nogc if (is(T == enum)) { // doesn't need `std.conv.to` switch (value) { static foreach (member; __traits(allMembers, T)) // prevents call to slower `EnumMembers` { case member: return __traits(getMember, T, member); // NOTE this is slower: mixin(`return T.` ~ member ~ `;`); } default: return defaultValue; } }
Re: Nothrow std.conv.to with explicit default value
On Wednesday, 20 June 2018 at 09:54:29 UTC, Per Nordlöw wrote: T toDefaulted(T)(scope const(char)[] value, T defaultValue) @safe pure nothrow @nogc if (is(T == enum)) { switch (value) { static foreach (index, member; __traits(allMembers, T)) { case member: return cast(T)(index); } Oops, this doesn't work for enums with "holes". How do I most easily fix that? This is my solution: T toDefaulted(T)(scope const(char)[] value, T defaultValue) @safe pure nothrow @nogc if (is(T == enum)) { switch (value) { static foreach (member; __traits(allMembers, T)) { case member: mixin(`return T.` ~ member ~ `;`); } default: return defaultValue; } } Is there a way to avoid compile-time-string-concat plus mixin here?
Re: Nothrow std.conv.to with explicit default value
On Wednesday, June 20, 2018 09:37:00 Per Nordlöw via Digitalmars-d-learn wrote: > On Wednesday, 20 June 2018 at 09:27:14 UTC, Per Nordlöw wrote: > > On Monday, 18 June 2018 at 21:10:03 UTC, Steven Schveighoffer > > > > wrote: > >> It just means re-doing std.conv.to, which is pretty hairy, but > >> also pretty well-organized. > > > > Ok. Where in std.conv do the string-to-enum conversions take > > place? > > AFAICT, string-to-enum-conversion must include a switch > containing a static foreach over all the enumerators, right? If you want to know where std.conv deals with converting enums, look for EnumMembers, since that's the trait to get all of the members of an enum. - Jonathan M Davis
Re: Nothrow std.conv.to with explicit default value
On Wednesday, 20 June 2018 at 09:37:00 UTC, Per Nordlöw wrote: AFAICT, string-to-enum-conversion must include a switch containing a static foreach over all the enumerators, right? My suggestion for nothrow @nogc string-to-enum conversion with default value T toDefaulted(T)(scope const(char)[] value, T defaultValue) @safe pure nothrow @nogc if (is(T == enum)) { switch (value) { static foreach (index, member; __traits(allMembers, T)) { case member: return cast(T)(index); } default: return defaultValue; } } @safe pure nothrow /*TODO @nogc*/ unittest { enum E { unknown, x, y, z } assert("x".toDefaulted!(E)(E.init) == E.x); assert("_".toDefaulted!(E)(E.init) == E.unknown); }
Re: Nothrow std.conv.to with explicit default value
On Wednesday, 20 June 2018 at 09:52:04 UTC, Per Nordlöw wrote: My suggestion for nothrow @nogc string-to-enum conversion with default value T toDefaulted(T)(scope const(char)[] value, T defaultValue) @safe pure nothrow @nogc if (is(T == enum)) { switch (value) { static foreach (index, member; __traits(allMembers, T)) { case member: return cast(T)(index); } Oops, this doesn't work for enums with "holes". How do I most easily fix that?
Re: Nothrow std.conv.to with explicit default value
On Wednesday, 20 June 2018 at 09:27:14 UTC, Per Nordlöw wrote: On Monday, 18 June 2018 at 21:10:03 UTC, Steven Schveighoffer wrote: It just means re-doing std.conv.to, which is pretty hairy, but also pretty well-organized. Ok. Where in std.conv do the string-to-enum conversions take place? AFAICT, string-to-enum-conversion must include a switch containing a static foreach over all the enumerators, right?
Re: Nothrow std.conv.to with explicit default value
On Monday, 18 June 2018 at 21:10:03 UTC, Steven Schveighoffer wrote: It just means re-doing std.conv.to, which is pretty hairy, but also pretty well-organized. Ok. Where in std.conv do the string-to-enum conversions take place?
Re: Nothrow std.conv.to with explicit default value
On 6/18/18 4:48 PM, Per Nordlöw wrote: The problem with this code is that throwing exceptions for the default case is costly at least with dmd. Is there another way to do this? Yes, have an internal implementation which doesn't throw, but rather returns an error code. Then you can call that and throw or use default value based on the return value. It just means re-doing std.conv.to, which is pretty hairy, but also pretty well-organized. -Steve
Re: Nothrow std.conv.to with explicit default value
On Monday, 18 June 2018 at 20:48:55 UTC, Per Nordlöw wrote: T toDefaulted(T, S, U)(S value, /*lazy*/ U defaultValue) if (is(typeof(() { T r = defaultValue; }))) // TODO use std.traits.isAssignable!(T, U) ? why not just make it T toDefaulted(T, S)(S value, T defaultValue) and forget U entirely? The problem with this code is that throwing exceptions for the default case is costly at least with dmd. Is there another way to do this? It depends on what the types are. If it is like string to int, you can simply scan the string for the appropriate format. For other conversions though, I don't think you can tell in general. User-defined types might not even tell you except by exception.
Nothrow std.conv.to with explicit default value
I have a nothrow variant of std.conv.to defined as follows: T toDefaulted(T, S, U)(S value, /*lazy*/ U defaultValue) if (is(typeof(() { T r = defaultValue; }))) // TODO use std.traits.isAssignable!(T, U) ? { try { import std.conv : to; return value.to!T; } catch (Exception e) // assume `ConvException`. TODO can we capture `ConvException` instead make it inferred `nothrow` { return defaultValue; } } The problem with this code is that throwing exceptions for the default case is costly at least with dmd. Is there another way to do this?
Re: std.conv.to!string refuses to convert a char* to string.
Thank you, core.runtime.Runtime.initialize() fixed the issue. I am now able to use to!string as well. I found your posts and Ali Çehreli's posts on this subject. I think I have some understanding now.
Re: std.conv.to!string refuses to convert a char* to string.
On Saturday, 9 December 2017 at 06:14:36 UTC, Venkat wrote: Thanks for the quick response. std.string.fromStringz did the trick. I am not sure what was the deal with to!string. Be careful with fromStringz. It doesn't allocate a new string, so the returned string can easily become corrupted if the C string it's referencing falls off the stack. As for your problem with to!string, it isn't actually to!string that's the issue. It appears to have something to do with the memory allocated from the GC. I assume this is a shared library. Random thoughts -- Have you initialized DRuntime? Have you registered the calling thread with the GC?
Re: std.conv.to!string refuses to convert a char* to string.
Thanks for the quick response. std.string.fromStringz did the trick. I am not sure what was the deal with to!string.
Re: std.conv.to!string refuses to convert a char* to string.
On Saturday, 9 December 2017 at 05:55:21 UTC, Venkat wrote: I am trying out the DJni library (https://github.com/Monnoroch/DJni). For some reason std.conv.to!string doesn't want to convert a char* to a string.The lines below are taken from the log. I see that the last frame is at gc_qalloc. I am not sure why it failed there. Can anybody elaborate on what is going on here ? Thanks in advance. I've got no idea, but can you verify that you can print it with printf? Can you allocate other GC memory? Can you try using fromStringz instead of to!string and see what that does? Just shots in the dark...
std.conv.to!string refuses to convert a char* to string.
I am trying out the DJni library (https://github.com/Monnoroch/DJni). For some reason std.conv.to!string doesn't want to convert a char* to a string.The lines below are taken from the log. I see that the last frame is at gc_qalloc. I am not sure why it failed there. Can anybody elaborate on what is going on here ? Thanks in advance. 91 92 93 Stack: [0x7f749dfd9000,0x7f749e0da000], sp=0x7f749e0d8600, free space=1021k 94 Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code) 95 C [libPrompt.so+0x6b0cc] gc_qalloc+0x2c 96 C [libPrompt.so+0x7bf18] _D2rt8lifetime12__arrayAllocFNaNbmxC8TypeInfoxQlZS4core6memory8BlkInfo_+0xec 97 C [libPrompt.so+0x6c2fa] _d_newarrayU+0x86 98 C [libPrompt.so+0x593a7] _D6object__T4_dupTxaTaZQlFNaNbAxaZAa+0x1f 99 C [libPrompt.so+0x59384] _D6object__T11_trustedDupTxaTaZQtFNaNbNeAxaZAa+0x20 100 C [libPrompt.so+0x59360] _D6object__T3dupTaZQhFNaNbNdNfAxaZAa+0x20 101 C [libPrompt.so+0x5932a] _D3std4conv__T6toImplTAyaTPxaZQqFQhZ9__lambda2MFNaNbZQBf+0x3e 102 C [libPrompt.so+0x592ea] _D3std4conv__T6toImplTAyaTPxaZQqFNaNbQlZQs+0x16 103 C [libPrompt.so+0x592d1] _D3std4conv__T2toTAyaZ__TQlTPxaZQsFNaNbQlZQy+0x9 104 C [libPrompt.so+0x59289] Java_Prompt_getLine+0x61 105 j Prompt.getLine(Ljava/lang/String;)Ljava/lang/String;+0 106 j Prompt.main([Ljava/lang/String;)V+11 107 v ~StubRoutines::call_stub 108 V [libjvm.so+0x690c66] JavaCalls::call_helper(JavaValue*, methodHandle*, JavaCallArguments*, Thread*)+0x1056 109 V [libjvm.so+0x6d2072] jni_invoke_static(JNIEnv_*, JavaValue*, _jobject*, JNICallType, _jmethodID*, JNI_ArgumentPusher*, Thread*)+0x362 110 V [libjvm.so+0x6ee8da] jni_CallStaticVoidMethod+0x17a 111 C [libjli.so+0x7bdf] JavaMain+0x81f 112 C [libpthread.so.0+0x8184] start_thread+0xc4 113 114 Java frames: (J=compiled Java code, j=interpreted, Vv=VM code) 115 j Prompt.getLine(Ljava/lang/String;)Ljava/lang/String;+0 116 j Prompt.main([Ljava/lang/String;)V+11
Using std.conv.to with std.typecons.Typedef
I am trying to create 2 types which contain integral values but should not be compatible with each other. std.typecons.Typedef seems perfect for this: alias QuestionId = Typedef!(long, long.init, "QuestionId"); alias StudentId = Typedef!(long, long.init, "StudentId"); However I'm failing to use using std.conv.to: QuestionId q = to!QuestionId("34"); <-- gives compile errors (This is a reduced example, the actual use case is to use std.csv to read in a structure from file, which in turn calls to!xyz) How can I get std.conv to understand std.typecons.Typedef? In general, is there a better solution to orthogonal types than Typedef? Thanks, Saurabh
Re: Using std.conv.to with std.typecons.Typedef
On Monday, 11 January 2016 at 08:03:19 UTC, Saurabh Das wrote: How can I get std.conv to understand std.typecons.Typedef? You can do something like this: QuestionId q = to!(TypedefType!QuestionId)("43"); In general, is there a better solution to orthogonal types than Typedef? Typedef is a reasonably solution, for this in my opinion. togrue
Re: Using std.conv.to with std.typecons.Typedef
On Monday, 11 January 2016 at 12:15:55 UTC, Saurabh Das wrote: Any ideas? Yes. Because Typedef is introducing new Types, which csvReader doesn't know what they are, you'll need a little workaround and cast the values yourself. import std.csv, std.stdio, std.algorithm, std.range; enum csvTxt = "10, 20 30, 40 50, 50"; myStuff = csvTxt.csvReader!(Tuple!(long, long)) .map!(a => MyStuff(cast(QuestionId)a[0], cast(StudentId) a[1])) .array; The .map does nothing other as getting the information out of the Tuple 'a' and constructing a struct of the type MyStuff. togrue
Re: Using std.conv.to with std.typecons.Typedef
On Monday, 11 January 2016 at 12:01:30 UTC, Tobi G. wrote: On Monday, 11 January 2016 at 08:03:19 UTC, Saurabh Das wrote: How can I get std.conv to understand std.typecons.Typedef? You can do something like this: QuestionId q = to!(TypedefType!QuestionId)("43"); In general, is there a better solution to orthogonal types than Typedef? Typedef is a reasonably solution, for this in my opinion. togrue Oh excellent. Yes that works for a standalone conversion. Do you know how I can use this with std.csv? import std.typecons; alias QuestionId = Typedef!(long, long.init, "QuestionId"); alias StudentId = Typedef!(long, long.init, "StudentId"); struct MyStuff { QuestionId q; StudentId s; } void main() { import std.csv, std.stdio, std.algorithm, std.range; File("file.csv").byLine.joiner("\n").csvReader!(MyStuff)(null).array; } This doesn't work. But if MyStuff is defined as: struct MyStuff { int q, s; }, then it works. Any ideas?
Re: Using std.conv.to with std.typecons.Typedef
On Monday, 11 January 2016 at 12:59:05 UTC, Tobi G. wrote: On Monday, 11 January 2016 at 12:15:55 UTC, Saurabh Das wrote: Any ideas? Yes. Because Typedef is introducing new Types, which csvReader doesn't know what they are, you'll need a little workaround and cast the values yourself. import std.csv, std.stdio, std.algorithm, std.range; enum csvTxt = "10, 20 30, 40 50, 50"; myStuff = csvTxt.csvReader!(Tuple!(long, long)) .map!(a => MyStuff(cast(QuestionId)a[0], cast(StudentId) a[1])) .array; The .map does nothing other as getting the information out of the Tuple 'a' and constructing a struct of the type MyStuff. togrue Yes that does make sense. I could read in a POD struct and convert it to a typed one. Though I was hoping for a more elegant solution... This'll have to do I guess. Thanks!
Re: std.conv.to!string(array), strange compile error
On Saturday, 14 November 2015 at 12:46:21 UTC, Relja wrote: I've got this strange compile error using std.conv.to!string(double[3]) - or any static array type. It's called in toString override function of a template matrix class, I'm building as a D learning project. [...] Maybe try to use a full slice after a 'static if' in case the template type is static array: -- { ElementType!T[] something; static if (isStaticArray!T) something = value[]; // slice to get a dyn array else something = value; // already a dyn array } -- and you work on something when it only works on dyn array. You can also slice the whole static array each time the problem occurrs
Re: std.conv.to!string(array), strange compile error
On Saturday, 14 November 2015 at 12:55:52 UTC, BBaz wrote: On Saturday, 14 November 2015 at 12:46:21 UTC, Relja wrote: I've got this strange compile error using std.conv.to!string(double[3]) - or any static array type. It's called in toString override function of a template matrix class, I'm building as a D learning project. [...] Maybe try to use a full slice after a 'static if' in case the template type is static array: -- { ElementType!T[] something; static if (isStaticArray!T) something = value[]; // slice to get a dyn array else something = value; // already a dyn array } -- and you work on something when it only works on dyn array. You can also slice the whole static array each time the problem occurrs I'm not sure if I understand you fully, but I think you misunderstood me - std.conv.to!string() works on a static array, when called directly on the array object, but gives the compile error when called on the returning object from a function. Here is simpler example, which shows the same compile error: import std.conv; float[3] getFloat3() { return [1, 2, 3]; } void main() { getFloat3().to!string; // does not compile (new float[3]).to!string; // compiles } On this example, compiler error message is the same as above: source/app.d(10,12): Error: template std.conv.to cannot deduce function from argument types !(string)(float[3]), candidates are: /usr/include/dlang/dmd/std/conv.d(293,1):std.conv.to(T) dmd failed with exit code 1. But then again, your suggestion got me to try this: getFloat3()[].to!string; This does compile! Can somebody elaborate, and tell us whats going on here? I feel that this does not solve my issue, but only makes me stay away from calling std.conv.to in this way. Thanks, Relja
Re: std.conv.to!string(array), strange compile error
On 14.11.2015 15:17, Relja wrote: - std.conv.to!string() works on a static array, when called directly on the array object, but gives the compile error when called on the returning object from a function. [...] void main() { getFloat3().to!string; // does not compile (new float[3]).to!string; // compiles } `new float[3]` is not a static array. Its type is not `float[3]`, it's `float[]`.
Re: std.conv.to!string(array), strange compile error
On Saturday, 14 November 2015 at 14:30:06 UTC, anonymous wrote: On 14.11.2015 15:17, Relja wrote: - std.conv.to!string() works on a static array, when called directly on the array object, but gives the compile error when called on the returning object from a function. [...] void main() { getFloat3().to!string; // does not compile (new float[3]).to!string; // compiles } `new float[3]` is not a static array. Its type is not `float[3]`, it's `float[]`. Oh, my bad, sorry. No mather, issue still stands: float[3] array; array.to!string; // compiles
std.conv.to!string(array), strange compile error
I've got this strange compile error using std.conv.to!string(double[3]) - or any static array type. It's called in toString override function of a template matrix class, I'm building as a D learning project. Here is the toString method: override string toString() const { string outs; outs ~= "["; for (size_t i = 0; i < rows; ++i) { outs ~= this.opIndex(i, 0).to!string; for (size_t j = 1; j < cols; ++j) { outs~= ", " ~ this.opIndex(i, j).to!string; } if (i == rows - 1) // last row outs ~= "]"; else outs ~= ";\n"; } return outs; } And here is the opIndex (const version): const(T) opIndex(ulong r, ulong c) const in { assert(r < _rows && c < _cols); } body { return _begin[c*_strides[1] + r*_strides[0]]; } Error occurs on lines with "this.opIndex().to!string", when template type is static array, e.g. double[3]: source/matrix.d(248,30): Error: template std.conv.to cannot deduce function from argument types !(string)(const(double[3])), candidates are: /usr/include/dlang/dmd/std/conv.d(293,1): std.conv.to(T) source/matrix.d(251,37): Error: template std.conv.to cannot deduce function from argument types !(string)(const(double[3])), candidates are: /usr/include/dlang/dmd/std/conv.d(293,1):std.conv.to(T) source/main.d(17,2): Error: template instance matrix.Matrix!(double[3]) error instantiating Lines 248 and 251 are the opIndex.to!string calls. Anyhow, I've changed opIndex() calls in the toString with matrix array indexing implementation (_begin[row*col_stride + col*item_stride]), and the conversion works properly (as it should on any array type, and gives normal output). So I've made a little test with compile-time messages: override string toString() const { string outs; outs ~= "["; pragma(msg, typeof(_begin[0]).stringof); pragma(msg, typeof(this.opIndex(0, 0)).stringof); this._begin[0].to!string; (this.opIndex(0, 0)).to!string; . And here's the compile output: const(double[3]) const(double[3]) source/matrix.d(250): Error: template std.conv.to cannot deduce function from argument types !(string)(const(double[3])), candidates are: /usr/include/dlang/dmd/std/conv.d(293):std.conv.to(T) Line 250 is opIndex().to!string, line above compiles ok. So even opIndex has the same return type as the array itself, to!string produces compile error on the opIndex.to!string call, and on the array.to!string does not. Could this be a bug in the compiler, or am I doing something wrong with the opIndex (or any other) method declaration? System is x64 Manjaro linux(arch based distro), compiler is dmd v2.069 (up-to-date from AUR, as libphobos is), and I have no other D compilers installed. Im' not sure how to check exact version of the libphobos - if anyone can tell me how to check it, please tell me, and I'll post it. Any other suggestion about above code is welcome! Thanks, Relja Ljubobratovic
Re: std.conv.to!string(array), strange compile error
On 14.11.2015 15:40, Relja wrote: float[3] array; array.to!string; // compiles Alright, full test case: import std.conv; float[3] getFloat3() { return [1, 2, 3]; } void main() { getFloat3().to!string; // does not compile float[3] a; a.to!string; // compiles } Yeah, that's odd. Looking at std.conv, `to` is this [1]: template to(T) { T to(A...)(A args) if (!isRawStaticArray!A) { return toImpl!T(args); } // Fix issue 6175 T to(S)(ref S arg) if (isRawStaticArray!S) { return toImpl!T(arg); } } So static arrays are taken by reference. That explains why return values from functions are rejected: they're rvalues and can't be passed by reference. Apparently, that oddity is a fix for issue 6175 [2] which seems to be about `to` returning a slice of a local variable (which is bad). I don't know the details of the issue or the fix, but I've got a feeling that there must be a better fix. Taking the data by reference, but otherwise doing the same as before would mean that `to` simply slices a static array when asked to make a dynamic array of it, rather than copying the data. And indeed, that seems to be the case: float[] f() { import std.conv; float[3] a = [1, 2, 3]; return a.to!(float[]); } void main() { auto a = f(); import std.stdio; writeln(a); /* prints garbage */ } I don't know if that's considered acceptable. I'm not a fan. [1] https://github.com/D-Programming-Language/phobos/blob/48d57e36e74379291a52087fcd1aa0dc19ff9a70/std/conv.d#L293-L307 [2] https://issues.dlang.org/show_bug.cgi?id=6175
Re: std.conv.to!string(array), strange compile error
On Saturday, 14 November 2015 at 18:52:54 UTC, anonymous wrote: On 14.11.2015 15:40, Relja wrote: [...] Alright, full test case: import std.conv; [...] Great explanation! Thank you!
Struct toString works but not std.conv.to!string
I have defined a struct UTCOffset in https://github.com/nordlow/justd/blob/master/datetime_ex.d Everything works as desired except for import std.conv : to; assert(UTCOffset(+14, 0).to!string == "UTC+14:00"); which fails as /usr/include/dmd/phobos/std/conv.d(293,14): Error: template instance isRawStaticArray!() does not match template declaration isRawStaticArray(T, A...) datetime_ex.d(129,29): Error: cannot resolve type for UTCOffset(cast(ubyte)0u).this(cast(byte)14, cast(ubyte)0u).to!string I don't understand what's wrong.
Re: Struct toString works but not std.conv.to!string
On Tuesday, October 13, 2015 21:07:07 Nordlöw via Digitalmars-d-learn wrote: > I have defined a struct UTCOffset in > > https://github.com/nordlow/justd/blob/master/datetime_ex.d > > Everything works as desired except for > > import std.conv : to; > assert(UTCOffset(+14, 0).to!string == "UTC+14:00"); > > which fails as > > /usr/include/dmd/phobos/std/conv.d(293,14): Error: template > instance isRawStaticArray!() does not match template declaration > isRawStaticArray(T, A...) > datetime_ex.d(129,29): Error: cannot resolve type for > UTCOffset(cast(ubyte)0u).this(cast(byte)14, > cast(ubyte)0u).to!string > > I don't understand what's wrong. Just glancing at your code, you've marked toString with @property, which is kind of a weird thing to do, nd if we ever make @property enforce that it's not called with parens, then that code won't work. So, you might try moving that @property: to after toString and see if that fixes your problem. But given the error, my guess is that the problem relates to the fact that you templatized the constructor, which is often problematic, and whatever type introspection std.conv.to is doing could be choking on that. So, you should probably try making it so that the constructor isn't templatized and see if that fixes the problem. - Jonathan M Davis
Re: Struct toString works but not std.conv.to!string
On 10/13/2015 02:07 PM, Nordlöw wrote: I have defined a struct UTCOffset in https://github.com/nordlow/justd/blob/master/datetime_ex.d Everything works as desired except for import std.conv : to; assert(UTCOffset(+14, 0).to!string == "UTC+14:00"); which fails as /usr/include/dmd/phobos/std/conv.d(293,14): Error: template instance isRawStaticArray!() does not match template declaration isRawStaticArray(T, A...) datetime_ex.d(129,29): Error: cannot resolve type for UTCOffset(cast(ubyte)0u).this(cast(byte)14, cast(ubyte)0u).to!string I don't understand what's wrong. Reduced with a workaround: struct UTCOffset { import std.conv : to;// Move to module scope to compile string toString() const { return "hello"; } } void main() { import std.conv : to; UTCOffset().to!string; } This is an issue that I know to be known. :) I think it is about private definitions (isRawStaticArray) of modules not working outside? or when in inner scopes? Something like that... Ali
Re: Struct toString works but not std.conv.to!string
On Tuesday, 13 October 2015 at 22:21:43 UTC, Ali Çehreli wrote: Reduced with a workaround: struct UTCOffset { import std.conv : to;// Move to module scope to compile This introduces UTCOffset.to as an alias to std.conv.to. string toString() const { return "hello"; } } void main() { import std.conv : to; This ends up being ignored, because UTCOffset has a member called `to`. UTCOffset().to!string; This does not do call std.conv.to through UFCS. Instead, it calls UTCOffset's static alias of std.conv.to without an argument. That is: `UTCOffset().to!string;` = `UTCOffset.to!string;` = `std.conv.to!string;` }
Re: Struct toString works but not std.conv.to!string
On Tuesday, 13 October 2015 at 21:50:54 UTC, Jonathan M Davis wrote: Just glancing at your code, you've marked toString with @property, which is kind of a weird thing to do, nd if we ever make @property enforce that it's not called with parens, then that code won't work. So, you might try moving that @property: to after toString and see if that fixes your problem. But given the error, my guess is that the problem relates to the fact that you templatized the constructor, which is often problematic, and whatever type introspection std.conv.to is doing could be choking on that. So, you should probably try making it so that the constructor isn't templatized and see if that fixes the problem. - Jonathan M Davis None of you advice helped. Fortunately I found a solution: If I move import std.conv : to; into the function scopes the problem goes away. Thanks, anyway, for you time.
Re: Purity of std.conv.to!string
On Sunday, 27 September 2015 at 05:52:26 UTC, Jack Stouffer wrote: Please make an issue on https://issues.dlang.org and I'll take a look a this later. Most of the functions in std.conv are templated so it must be some internal function that's not properly annotated, or it's using manual memory management. Already file here: https://issues.dlang.org/show_bug.cgi?id=3437 https://issues.dlang.org/show_bug.cgi?id=4850
Re: Purity of std.conv.to!string
On 27/09/2015 3:14 AM, cym13 wrote: On Saturday, 26 September 2015 at 17:08:00 UTC, Nordlöw wrote: Why is the following code not pure: float x = 3.14; import std.conv : to; auto y = x.to!string; ??? Is there a reason for it not being pure? If not, this is a serious problem as this is such a fundamental function. Probably because it uses C's float formatting functions, and they probably set errno and therefore aren't pure. Maybe because of floating point numbers uncertainty that would cause the resulting string to be different for two equivalent inputs? I can't seem to put an example together though. No, it doesn't work like that.
Re: Purity of std.conv.to!string
On Saturday, 26 September 2015 at 17:08:00 UTC, Nordlöw wrote: Why is the following code not pure: float x = 3.14; import std.conv : to; auto y = x.to!string; ??? Is there a reason for it not being pure? If not, this is a serious problem as this is such a fundamental function. I don't know the exact reason but I found a couple of functions which could be marked pure which are not, including strippedOctalLiteral and isOctalLiteralString. It's possible that some function was simply overlooked and needs to be marked pure or infer purity. The larger issue at hand is that the compiler doesn't tell you where an impurity lies, merely that it exists. I mentioned this issue not too long ago while experiencing my own difficulties respecting purity.
Re: Purity of std.conv.to!string
On Saturday, 26 September 2015 at 17:08:00 UTC, Nordlöw wrote: Why is the following code not pure: float x = 3.14; import std.conv : to; auto y = x.to!string; ??? Is there a reason for it not being pure? If not, this is a serious problem as this is such a fundamental function. Maybe because of floating point numbers uncertainty that would cause the resulting string to be different for two equivalent inputs? I can't seem to put an example together though.
Purity of std.conv.to!string
Why is the following code not pure: float x = 3.14; import std.conv : to; auto y = x.to!string; ??? Is there a reason for it not being pure? If not, this is a serious problem as this is such a fundamental function.
Re: Purity of std.conv.to!string
On Saturday, 26 September 2015 at 17:08:00 UTC, Nordlöw wrote: Why is the following code not pure: float x = 3.14; import std.conv : to; auto y = x.to!string; ??? Is there a reason for it not being pure? If not, this is a serious problem as this is such a fundamental function. Please make an issue on https://issues.dlang.org and I'll take a look a this later. Most of the functions in std.conv are templated so it must be some internal function that's not properly annotated, or it's using manual memory management.
Re: Fuzzy Levenshtein variant of std.conv.to
On Tuesday, 28 April 2015 at 23:09:27 UTC, Per Nordlöw wrote: On Tuesday, 28 April 2015 at 16:20:24 UTC, Per Nordlöw wrote: I update my Github repo. I had forgotten to push my latest changes. I solved it.
Re: Fuzzy Levenshtein variant of std.conv.to
On Wednesday, 29 April 2015 at 14:46:04 UTC, Per Nordlöw wrote: On Tuesday, 28 April 2015 at 23:09:27 UTC, Per Nordlöw wrote: On Tuesday, 28 April 2015 at 16:20:24 UTC, Per Nordlöw wrote: I update my Github repo. I had forgotten to push my latest changes. I solved it. I started working on this yesterday before you solved it, and ended up finishing a solution. It was a fun excercise, thanks. https://gist.github.com/JakobOvrum/515737710619a9d97273 It uses a loop instead of a range composition because of the early return when the Levenshtein distance is 0; that would be clumsy to express with ranges.
Re: Fuzzy Levenshtein variant of std.conv.to
On Tuesday, 28 April 2015 at 16:20:24 UTC, Per Nordlöw wrote: I update my Github repo. I had forgotten to push my latest changes.
Fuzzy Levenshtein variant of std.conv.to
At https://github.com/nordlow/justd/blob/master/conv_ex.d I'm trying to figure out how to best implement a fuzzy variant of std.conv.to when converting a string to an enum. I'm almost there but I'm uncertain how to best pick the index of the smallest element in `distances` and then convert it to the corresponding enumerator for when `U` is an enum. Help please.
opCast and std.conv.to
I tried to override the opCast operator in a class to be able to explicitly convert the class to a string, but to!string just returns the name of the class. Do opCast and to! together not work with strings and does that mean that i have to use alias this?
Re: opCast and std.conv.to
On Sunday, 22 February 2015 at 13:04:56 UTC, Jacques Müller wrote: I tried to override the opCast operator in a class to be able to explicitly convert the class to a string, but to!string just returns the name of the class. to!string actually forwards to a special function, string toString() {} which you'll need to implement and override from the base class. It might need to be const too override string toString() const { } the compiler will tell you.
Re: opCast and std.conv.to
On Sunday, 22 February 2015 at 13:15:31 UTC, Adam D. Ruppe wrote: to!string actually forwards to a special function, string toString() {} which you'll need to implement and override from the base class. Thanks, that's good to know. I was just wondering why my code wasn't working correctly.
Re: std.conv.to purity
On Sat, 14 Feb 2015 11:29:28 +, Jack Applegame wrote: why std.conv.to is not pure? string foo(real v) pure { return v.to!string; } // Error: pure function 'foo' cannot call impure function 'std.conv.to!string.to!(real).to' 'cause float-string conversion is damned hard task. to perform this conversion `to!` falls back to `formatValue` from std.format, which in turn using `snprintf()` from libc. signature.asc Description: PGP signature
std.conv.to purity
why std.conv.to is not pure? string foo(real v) pure { return v.to!string; } // Error: pure function 'foo' cannot call impure function 'std.conv.to!string.to!(real).to'
Re: std.conv.to purity
On Saturday, 14 February 2015 at 12:24:51 UTC, ketmar wrote: On Sat, 14 Feb 2015 11:29:28 +, Jack Applegame wrote: why std.conv.to is not pure? string foo(real v) pure { return v.to!string; } // Error: pure function 'foo' cannot call impure function 'std.conv.to!string.to!(real).to' 'cause float-string conversion is damned hard task. to perform this conversion `to!` falls back to `formatValue` from std.format, which in turn using `snprintf()` from libc. Forgive me being a bit dense but that doesn't necessarily mean it's impure though, right?
Re: std.conv.to purity
On Sat, 14 Feb 2015 19:59:58 +, Gary Willoughby wrote: On Saturday, 14 February 2015 at 12:24:51 UTC, ketmar wrote: On Sat, 14 Feb 2015 11:29:28 +, Jack Applegame wrote: why std.conv.to is not pure? string foo(real v) pure { return v.to!string; } // Error: pure function 'foo' cannot call impure function 'std.conv.to!string.to!(real).to' 'cause float-string conversion is damned hard task. to perform this conversion `to!` falls back to `formatValue` from std.format, which in turn using `snprintf()` from libc. Forgive me being a bit dense but that doesn't necessarily mean it's impure though, right? yes, you are right, it *may* be pure. yet `snprintf()` can't be marked as `pure`, so it contaminates everything. and there are no guarantees that `snprintf()` is pure even for known arguments (compiler can't prove that, and libc is free to do any funny things in it), so it will be wrong to just force-reimport it as `pure`. tl;dr: we need native D float-string converter to allow purity in this case. you are free to force-hack purity flag on function if you want, but this can be wrong and may lead to various heisenbugs. native pure D converter will also allow CTFE, btw, which is impossible now. signature.asc Description: PGP signature
Re: std.conv.to purity
While snprintf might be one thing that provides to be an interesting obstacle, the better answer to why std.conv.to isnt pure is that no one has invested the time to work through issues like that to make it so. It _should_ be pure. On 2/14/2015 12:32 PM, ketmar via Digitalmars-d-learn wrote: On Sat, 14 Feb 2015 19:59:58 +, Gary Willoughby wrote: On Saturday, 14 February 2015 at 12:24:51 UTC, ketmar wrote: On Sat, 14 Feb 2015 11:29:28 +, Jack Applegame wrote: why std.conv.to is not pure? string foo(real v) pure { return v.to!string; } // Error: pure function 'foo' cannot call impure function 'std.conv.to!string.to!(real).to' 'cause float-string conversion is damned hard task. to perform this conversion `to!` falls back to `formatValue` from std.format, which in turn using `snprintf()` from libc. Forgive me being a bit dense but that doesn't necessarily mean it's impure though, right? yes, you are right, it *may* be pure. yet `snprintf()` can't be marked as `pure`, so it contaminates everything. and there are no guarantees that `snprintf()` is pure even for known arguments (compiler can't prove that, and libc is free to do any funny things in it), so it will be wrong to just force-reimport it as `pure`. tl;dr: we need native D float-string converter to allow purity in this case. you are free to force-hack purity flag on function if you want, but this can be wrong and may lead to various heisenbugs. native pure D converter will also allow CTFE, btw, which is impossible now.
std.conv.to vs. casting
I'm having trouble understanding the difference between casting and std.conv.to. Any help?
Re: std.conv.to vs. casting
On Thursday, 4 July 2013 at 06:18:21 UTC, CJS wrote: I'm having trouble understanding the difference between casting and std.conv.to. Any help? Casting merely changes the observed type, whereas to does a deep conversion. Observe: import std.stdio; import std.conv; void main() { int[] ints = [1, 2, 3]; auto bytes1 = cast(ubyte[])(ints); auto bytes2 = to!(ubyte[])(ints); writeln(bytes1); writeln(bytes2); } [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0] [1, 2, 3] To is very useful to do true type conversion. It can change string width. Finally, to is able to do string interpretation. EG: import std.stdio; import std.conv; void main() { int[] ints = to!(int[])([1, 2, 3]); writeln(ints); } [1, 2, 3] To is very convenient because it is a one stop shop: It doesn't matter what you want to do: to will do it. You don't need to mix/match calls to atoi/itoa/encode/decode etc. Furthermore, it is safe: if anything fails, to will throw. It will also throw if you overflow: import std.conv; void main() { int a = 500; ubyte b = cast(ubyte)(a); //No problem here: Silent overflow ubyte c = to!ubyte(a);//Runtime overflow exception } Hope that helps :)
Re: std.conv.to vs. casting
On 07/04/2013 10:14 AM, monarch_dodra wrote: Casting merely changes the observed type, whereas to does a deep conversion. What are the speed implications of to compared to cast? I ask because I see various casts in Phobos, and wonder if there isn't improved safety in preferring instead to use to, so long as the optimal speed is there with appropriate compiler optimizations. I'm particularly concerned here because of a bug I observed that would have been caught if to had been used rather than cast: http://d.puremagic.com/issues/show_bug.cgi?id=10322#c4 (I'm working on a fix, it's just time constraints that have delayed delivering it:-)
Re: std.conv.to vs. casting
On Thursday, 4 July 2013 at 09:31:42 UTC, Joseph Rushton Wakeling wrote: On 07/04/2013 10:14 AM, monarch_dodra wrote: Casting merely changes the observed type, whereas to does a deep conversion. What are the speed implications of to compared to cast? I ask because I see various casts in Phobos, and wonder if there isn't improved safety in preferring instead to use to, so long as the optimal speed is there with appropriate compiler optimizations. I'm particularly concerned here because of a bug I observed that would have been caught if to had been used rather than cast: http://d.puremagic.com/issues/show_bug.cgi?id=10322#c4 (I'm working on a fix, it's just time constraints that have delayed delivering it:-) Speed implications, it mostly only means doing an if (a T.max). It also means adding code to handle a throw. Finally, it means the function can't be marked nothrow. I'd argue that to should really only be used for legitimate cases where the runtime can create out of range values, and you want to catch that as an exception. Speed should not be a real issue*. I didn't go into the details, but in your bug report, it seems like it is more of an implementation error ? In that case, an ERROR would be better. *Speed wise, it is not a problem I'd say, except maybe in range primitives, espcially empty, front and opIndex, and to a certain, popFront. It depends on the relative cost of the operation of course. For example: Cycle provides RA indexing. the code is written as: return source[(currentIndex + inputIndex) % length]; In this specific case, there is an overflow risk, even though RA access should be un-bounded. However, it is not checked, as the implications to calling to would be problematic. Placing an assert there is better, so release does not have to pay for the check.
Re: std.conv.to vs. casting
On Thursday, 4 July 2013 at 10:32:26 UTC, Joseph Rushton Wakeling wrote: I can prepare a reduced example but it's probably simpler for me to just prepare a bugfix and do some benchmarks. By the way, CJS -- sorry to have hijacked your query. But I think you had your answer already :-)
Re: std.conv.to vs. casting
On Thursday, 4 July 2013 at 10:23:22 UTC, monarch_dodra wrote: I'm trying to read the bug entry, but I don't get it. Maybe a reduced case to explain? Point is, the skip() function in std.random.RandomSample can be called with the floating-point variable _Vprime equal to nan, _if_ popFront() or index() are called before front(). If isNan(_Vprime) !_algorithmA then skip() will generate incorrect results. I was asking about the speed of isNan compared to if(boolean) because I was considering killing the bool _first and just using isNan(_Vprime) to check if the first sample point has already been generated. I can prepare a reduced example but it's probably simpler for me to just prepare a bugfix and do some benchmarks.
Re: std.conv.to vs. casting
By the way, CJS -- sorry to have hijacked your query. But I think you had your answer already :-) Yes. It was a very helpful answer. I'm just glad the question I asked was apparently relevant to other users as well.
Re: std.conv.to vs. casting
On 07/04/2013 03:15 AM, Joseph Rushton Wakeling wrote: The cast should be safe, as it's a size_t to a double. I am commenting without fully understanding the context: Both size_t and double are 64 bit types on a 64-bit system. double.mant_dig being 53, converting from size_t to double loses information for many values. import std.stdio; import std.conv; void main() { size_t i = 0x8000___0001; double d0 = i.to!double; double d1 = cast(double)i; writefln(%s, i); writefln(%f, d0); writefln(%f, d1); } Prints 9223372036854775809 9223372036854775808.00 9223372036854775808.00 Still, the same information loss in a comparison may make one think that it actually worked! :p assert(d0 == i);// passes! assert(d1 == i);// passes! Ali
Re: std.conv.to vs. casting
On Thu, Jul 04, 2013 at 06:43:16PM +0200, Joseph Rushton Wakeling wrote: On 07/04/2013 06:16 PM, Ali Çehreli wrote: I am commenting without fully understanding the context: Both size_t and double are 64 bit types on a 64-bit system. double.mant_dig being 53, converting from size_t to double loses information for many values. Oh, bugger. You mean that because it needs space to store the exponent, it has a reduced number of significant figures compared to size_t? [...] Yes. See: http://en.wikipedia.org/wiki/Double-precision_floating-point_format Of the 64 bits, only 53 are available for storing the mantissa (well, actually 52, but the first bit is always 1 except when the exponent is zero so it's not stored -- you get it for free). Of the remaining bits, 11 are reserved for storing the exponent, and the last for storing the sign. So the maximum precision a double can have is 53 bits. If you have a value that requires more than that, the representation will be inexact. T -- Programming is not just an act of telling a computer what to do: it is also an act of telling other programmers what you wished the computer to do. Both are important, and the latter deserves care. -- Andrew Morton
Re: std.conv.to vs. casting
On Thursday, 4 July 2013 at 16:16:08 UTC, Ali Çehreli wrote: On 07/04/2013 03:15 AM, Joseph Rushton Wakeling wrote: The cast should be safe, as it's a size_t to a double. I am commenting without fully understanding the context: Both size_t and double are 64 bit types on a 64-bit system. double.mant_dig being 53, converting from size_t to double loses information for many values. It's not about losing information, it's about being out of range. For example, to!float(2.0^^50) will throw an exception.
Re: std.conv.to can't convert to bool?
Andrej Mitrovic Wrote: Wow not a minute later and I get bitten by my own solution. A C function returned 1 for a supported feature, and -1 otherwise. And of course -1 got converted to true, so then I had a bug in my code. Damn silly C functions which return -1 when they should return 0. Or damn me for not RTFM'ing. Yeah, so the reason it doesn't do that conversion is because it will bite you. Actually D already uses non-zero as true. Why do you need to cast it?
std.conv.to can't convert to bool?
import std.stdio; import std.conv : to; void main() { uint state = 1; writeln( to!bool(state) ); } D:\DMD\dmd2\windows\bin\..\..\src\phobos\std\conv.d(99): Error: template std.conv.toImpl(T,S) if (!implicitlyConverts!(S,T) isSomeString!(T) isInputRange!(Unqual!(S)) isSomeChar!(ElementType!(S))) does not match any function template declaration D:\DMD\dmd2\windows\bin\..\..\src\phobos\std\conv.d(99): Error: template std.conv.toImpl(T,S) if (!implicitlyConverts!(S,T) isSomeString!(T) isInputRange!(Unqual!(S)) isSomeChar!(ElementType!(S))) cannot deduce template function from argument types !(bool)(uint) D:\DMD\dmd2\windows\bin\..\..\src\phobos\std\conv.d(99): Error: template instance errors instantiating template boolConv.d(9): Error: template instance std.conv.to!(bool).to!(uint) error instantiating What's the big problem with converting an int/uint to bool? I'm using a cast for now.
Re: std.conv.to can't convert to bool?
Wow not a minute later and I get bitten by my own solution. A C function returned 1 for a supported feature, and -1 otherwise. And of course -1 got converted to true, so then I had a bug in my code. Damn silly C functions which return -1 when they should return 0. Or damn me for not RTFM'ing.