Re: impure
On Monday, 8 April 2024 at 07:53:01 UTC, Dom DiSc wrote: On Sunday, 24 March 2024 at 07:41:41 UTC, Dom DiSc wrote: Try `debug unittest {...}`? Cool. This seems to work. That's a nice workaroud for tests. Yay! Nice, fyi, you can use it with statements inside function bodies as well. Usefull for doing logging in pure functions.
Re: impure
On Monday, 8 April 2024 at 07:03:40 UTC, Alexandru Ermicioi wrote: On Sunday, 24 March 2024 at 07:41:41 UTC, Dom DiSc wrote: I'm creating a library that is completely pure, but it doesn't compile with pure: at the top because of one impure unittest (which uses random to test some things only probabilistic)! So do I really need to declare every function pure individually because of a test?!? Can we please have a @impure attribute? And by the way also @throws and @gc? That would make live so much easier... Try `debug unittest {...}`? Cool. This seems to work. That's a nice workaroud for tests. Yay!
Re: impure
On Sunday, 7 April 2024 at 23:32:24 UTC, MrJay wrote: A better way to apply a attribute to an entire file is to use an explicit scope you can still apply this to basically the entire file but leave the tests out of it. Better than an explicit impure (or pure=false) attribute? I don't think so. It heavily uglyfies the file, as single items without a specific attribute are interspersed in the file. So the scope need to end before and start again after the affected function or test. An it stops working at all if e.g. one test is impure and another test is @gc, because then the scopes overlap and can no more be contained in each other. Really, having the counter-attributes would improve the language.
Re: impure
On Sunday, 24 March 2024 at 07:41:41 UTC, Dom DiSc wrote: I'm creating a library that is completely pure, but it doesn't compile with pure: at the top because of one impure unittest (which uses random to test some things only probabilistic)! So do I really need to declare every function pure individually because of a test?!? Can we please have a @impure attribute? And by the way also @throws and @gc? That would make live so much easier... Try `debug unittest {...}`?
Re: impure
On Sunday, 24 March 2024 at 07:41:41 UTC, Dom DiSc wrote: I'm creating a library that is completely pure, but it doesn't compile with pure: at the top because of one impure unittest (which uses random to test some things only probabilistic)! So do I really need to declare every function pure individually because of a test?!? Can we please have a @impure attribute? And by the way also @throws and @gc? That would make live so much easier... A better way to apply a attribute to an entire file is to use an explicit scope you can still apply this to basically the entire file but leave the tests out of it. second since these are test its better for them to be pure, so use debug as it implicitly tells you where all global mutation happen, if you need your unit tests to run without debug for what ever reason fall back to suggestion one. `dmd test.d -debug` ``` d // File name test.d import std.stdio; int var = 0; void main() { writeln(var); var = 1; writeln(var); foo(); writeln(var); baz(); writeln(var); } pure { int foo() { debug { var = 2;} return 2; } // you can nest scopes @safe { int bar () { return 3; } } } void baz() { var = 4; } ```
Re: impure
On Friday, April 5, 2024 3:11:42 AM MDT Dom DiSc via Digitalmars-d-learn wrote: > On Sunday, 24 March 2024 at 09:16:20 UTC, Jonathan M Davis wrote: > > So, yes, you've run into a problem that it would be nice to > > have a better fix for, but even if we could negate attributes > > in general, there are good reasons to prefer to avoid > > mass-applying attributes. > > I don't see it as "mass-applying attributes" rather than changing > the default to something more sane, so that I have to apply > *less* attributes to any single function. The core issue is that the place that is applying the attributes is far from what they're being applied to, which makes it extremely easy to miss them and not know which attributes are actually being applied - particularly when reviewing code, since then you tend to be looking primarily at diffs and not the entire file. It's going to be less of a problem with personal projects, but with any project where multiple people work on the code, it can start being a problem. Ultimately, having the attributes directly on what they apply to tends to result in fewer maintenance issues - particularly with larger projects. > If the addition of new keywords (like "throws", "@gc" and > "impure") is a problem, why not doing it like @nogc(false) or > @nogc=false (likewise for nothrow and pure)? There are a number of ways that it could be done, but regardless, we'd need a DIP and an implementation, and neither has happened. It's a known problem but hasn't been a big enough problem to have been made a priority. - Jonathan M Davis
Re: impure
On Sunday, 24 March 2024 at 09:16:20 UTC, Jonathan M Davis wrote: So, yes, you've run into a problem that it would be nice to have a better fix for, but even if we could negate attributes in general, there are good reasons to prefer to avoid mass-applying attributes. I don't see it as "mass-applying attributes" rather than changing the default to something more sane, so that I have to apply *less* attributes to any single function. If the addition of new keywords (like "throws", "@gc" and "impure") is a problem, why not doing it like @nogc(false) or @nogc=false (likewise for nothrow and pure)?
Re: impure
On Sunday, March 24, 2024 1:41:41 AM MDT Dom DiSc via Digitalmars-d-learn wrote: > I'm creating a library that is completely pure, but it doesn't > compile with pure: at the top because of one impure unittest > (which uses random to test some things only probabilistic)! > > So do I really need to declare every function pure individually > because of a test?!? > > Can we please have a @impure attribute? > And by the way also @throws and @gc? > That would make live so much easier... It's been brought up a number of times before that it would be desirable to have a way to negate attributes, and maybe we'll get that ability at some point, but for now, we don't have it. The only attributes that can be negated are @safe, @trusted, and @system, because using one of them directly on a function overrides any others that are applied more globally. So, for now, you cannot apply pure to an entire module and then have it not apply to something within the module (though you could put that one test at the top before you apply pure). Another thing you could do would be to use debug {} to ignore attributes within that block (though then that code will only be run when building with -debug). How much sense that makes depends on what your test is doing, but it is a way to get around pure in code that isn't intended to be used in production. All of that being said, I'd be inclined to argue that in general, mass-applying attributes is asking for trouble. It works to a point, but it makes it easy to forget which attributes apply, and in some cases, attributes get ignored when they're mass-applied (though that's mostly on types IIRC). It makes more sense when you're applying an attribute to the entire module and not just a section of a module, but it does have a tendency to become a maintenance problem - particularly when it's code that more than one person works on. It also makes code harder to review, because diffs won't include any of the attributes that are being mass-applied, making it easy to miss the fact that a particular attribute applies to the code being changed. So, yes, you've run into a problem that it would be nice to have a better fix for, but even if we could negate attributes in general, there are good reasons to prefer to avoid mass-applying attributes. - Jonathan M Davis
Re: cannot call impure function
On Sunday, 4 October 2020 at 18:02:11 UTC, Michael wrote: On Sunday, 4 October 2020 at 17:43:13 UTC, Michael wrote: [...] I used the dmg file: dmd.2.094.0.dmg I reinstalled using the installation script (install.sh) and now it works. Still don't know why the dmg-based intstallation did not work. https://dlang.org/install.html Anyway, thanks for your responses! I think there might have been a mismatch between the compiler used, and the Phobos library used. This might happen if you used multiple sources for installation, e.g. brew / macports / dmg (install script is self contained and never affected).
Re: cannot call impure function
On Sunday, 4 October 2020 at 17:43:13 UTC, Michael wrote: On Sunday, 4 October 2020 at 17:37:52 UTC, Mathias LANG wrote: On Sunday, 4 October 2020 at 17:05:33 UTC, Michael wrote: On Sunday, 4 October 2020 at 17:01:44 UTC, Paul Backus wrote: On Sunday, 4 October 2020 at 16:48:24 UTC, Michael wrote: Dear all, Sorry for the potentially stupid question, but I'm a complete newbie to D. Why does compiling the following trivial code fail? import std.stdio; void main() { writeln(3.14); } Works fine for me using DMD 2.094.0 on Linux. What OS and compiler version are you using, and how did you install DMD? DMD64 D Compiler v2.094.0 on macOS 10.15.6 I cannot reproduce locally (macOS 10.15.6 too). How did you install DMD ? I used the dmg file: dmd.2.094.0.dmg I reinstalled using the installation script (install.sh) and now it works. Still don't know why the dmg-based intstallation did not work. https://dlang.org/install.html Anyway, thanks for your responses!
Re: cannot call impure function
On Sunday, 4 October 2020 at 17:37:52 UTC, Mathias LANG wrote: On Sunday, 4 October 2020 at 17:05:33 UTC, Michael wrote: On Sunday, 4 October 2020 at 17:01:44 UTC, Paul Backus wrote: On Sunday, 4 October 2020 at 16:48:24 UTC, Michael wrote: Dear all, Sorry for the potentially stupid question, but I'm a complete newbie to D. Why does compiling the following trivial code fail? import std.stdio; void main() { writeln(3.14); } Works fine for me using DMD 2.094.0 on Linux. What OS and compiler version are you using, and how did you install DMD? DMD64 D Compiler v2.094.0 on macOS 10.15.6 I cannot reproduce locally (macOS 10.15.6 too). How did you install DMD ? I used the dmg file: dmd.2.094.0.dmg
Re: cannot call impure function
On Sunday, 4 October 2020 at 16:48:24 UTC, Michael wrote: Dear all, Sorry for the potentially stupid question, but I'm a complete newbie to D. Why does compiling the following trivial code fail? [...] I have tried my best to make it fail, but can't. Maybe it's something with the combination of dmd64 and MACOS?
Re: cannot call impure function
On Sunday, 4 October 2020 at 17:05:33 UTC, Michael wrote: On Sunday, 4 October 2020 at 17:01:44 UTC, Paul Backus wrote: On Sunday, 4 October 2020 at 16:48:24 UTC, Michael wrote: Dear all, Sorry for the potentially stupid question, but I'm a complete newbie to D. Why does compiling the following trivial code fail? import std.stdio; void main() { writeln(3.14); } Works fine for me using DMD 2.094.0 on Linux. What OS and compiler version are you using, and how did you install DMD? DMD64 D Compiler v2.094.0 on macOS 10.15.6 I cannot reproduce locally (macOS 10.15.6 too). How did you install DMD ?
Re: cannot call impure function
On Sunday, 4 October 2020 at 17:05:33 UTC, Michael wrote: On Sunday, 4 October 2020 at 17:01:44 UTC, Paul Backus wrote: On Sunday, 4 October 2020 at 16:48:24 UTC, Michael wrote: Dear all, Sorry for the potentially stupid question, but I'm a complete newbie to D. Why does compiling the following trivial code fail? import std.stdio; void main() { writeln(3.14); } Works fine for me using DMD 2.094.0 on Linux. What OS and compiler version are you using, and how did you install DMD? DMD64 D Compiler v2.094.0 on macOS 10.15.6 I did not use any compiler flags, but just: dmd test1.d
Re: cannot call impure function
On Sunday, 4 October 2020 at 17:01:44 UTC, Paul Backus wrote: On Sunday, 4 October 2020 at 16:48:24 UTC, Michael wrote: Dear all, Sorry for the potentially stupid question, but I'm a complete newbie to D. Why does compiling the following trivial code fail? import std.stdio; void main() { writeln(3.14); } Works fine for me using DMD 2.094.0 on Linux. What OS and compiler version are you using, and how did you install DMD? DMD64 D Compiler v2.094.0 on macOS 10.15.6
Re: cannot call impure function
On Sunday, 4 October 2020 at 16:48:24 UTC, Michael wrote: Dear all, Sorry for the potentially stupid question, but I'm a complete newbie to D. Why does compiling the following trivial code fail? import std.stdio; void main() { writeln(3.14); } Works fine for me using DMD 2.094.0 on Linux. What OS and compiler version are you using, and how did you install DMD?
cannot call impure function
Dear all, Sorry for the potentially stupid question, but I'm a complete newbie to D. Why does compiling the following trivial code fail? import std.stdio; void main() { writeln(3.14); } Error message: /Library/D/dmd/src/phobos/std/format.d(1601): Error: pure function std.format.FormatSpec!char.FormatSpec.toString cannot call impure function std.format.FormatSpec!char.FormatSpec.toString!(Appender!string).toString /Library/D/dmd/src/phobos/std/format.d(478): Error: template instance std.format.FormatSpec!char error instantiating /Library/D/dmd/src/phobos/std/stdio.d(1590):instantiated from here: formattedWrite!(LockingTextWriter, char, double) /Library/D/dmd/src/phobos/std/stdio.d(3927):instantiated from here: write!(double, char) test1.d(5):instantiated from here: writeln!double Cheers, Michael
Re: Why is there no throws, @gc, impure, mutable ?
On Monday, 7 September 2020 at 11:44:40 UTC, Paul Backus wrote: On Monday, 7 September 2020 at 11:25:15 UTC, wjoe wrote: It's easy to declare the entire module @safe and functions which can't be can be declared @system. However there is const, immutable, pure, @nogc and nothrow but no mutable, impure, @gc and throws. Why is that ? Mostly because nobody's bothered to add them (yet). There's an accepted proposal to add a "throw" attribute as the opposite of nothrow [1], but it looks like it still hasn't been implemented in the compiler. For const and immutable, you can use std.traits.Unconst [2] to remove them in most cases. [1] https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1029.md [2] http://dpldocs.info/experimental-docs/std.traits.Unconst.html Very interesting. Thanks.
Re: Why is there no throws, @gc, impure, mutable ?
On Monday, 7 September 2020 at 11:25:15 UTC, wjoe wrote: It's easy to declare the entire module @safe and functions which can't be can be declared @system. However there is const, immutable, pure, @nogc and nothrow but no mutable, impure, @gc and throws. Why is that ? Mostly because nobody's bothered to add them (yet). There's an accepted proposal to add a "throw" attribute as the opposite of nothrow [1], but it looks like it still hasn't been implemented in the compiler. For const and immutable, you can use std.traits.Unconst [2] to remove them in most cases. [1] https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1029.md [2] http://dpldocs.info/experimental-docs/std.traits.Unconst.html
Why is there no throws, @gc, impure, mutable ?
It's easy to declare the entire module @safe and functions which can't be can be declared @system. However there is const, immutable, pure, @nogc and nothrow but no mutable, impure, @gc and throws. Why is that ?
Re: How to override impure function from pure function
On Tuesday, 13 December 2016 at 05:13:01 UTC, Nikhil Jacob wrote: I mistook the original statement to mean that an impure function can be called from a pure function with some manual overrides. Thank you for the clarification. Yeah you can't do that, except in a debug statement. You can however cheat with SetFunctionAttributes (from std.traits).
Re: How to override impure function from pure function
On Tuesday, 13 December 2016 at 04:48:11 UTC, Nikhil Jacob wrote: In the D spec for pure functions it says that a pure function can override "can override an impure function, but an impure function cannot override a pure one" Can anyone help me how to do this ? what this means is class Foo { void foo() { ... } } class Bar : Foo { override void foo() pure { ... } } is allowed. but int someglobal; class Foo { void foo() pure { ... } } class Bar : Foo { override void foo() { someglobal = 42; } } in not.
Re: How to override impure function from pure function
On Tuesday, 13 December 2016 at 05:10:02 UTC, Nicholas Wilson wrote: On Tuesday, 13 December 2016 at 04:48:11 UTC, Nikhil Jacob wrote: In the D spec for pure functions it says that a pure function can override "can override an impure function, but an impure function cannot override a pure one" Can anyone help me how to do this ? what this means is class Foo { void foo() { ... } } class Bar : Foo { override void foo() pure { ... } } is allowed. but int someglobal; class Foo { void foo() pure { ... } } class Bar : Foo { override void foo() { someglobal = 42; } } in not. I mistook the original statement to mean that an impure function can be called from a pure function with some manual overrides. Thank you for the clarification.
How to override impure function from pure function
In the D spec for pure functions it says that a pure function can override "can override an impure function, but an impure function cannot override a pure one" Can anyone help me how to do this ?
Re: cannot call impure function ~this
On Wednesday, 16 October 2013 at 07:58:09 UTC, Namespace wrote: On Wednesday, 16 October 2013 at 07:32:27 UTC, monarch_dodra wrote: On Wednesday, 16 October 2013 at 07:27:25 UTC, Namespace wrote: On Wednesday, 16 October 2013 at 07:23:45 UTC, monarch_dodra wrote: On Tuesday, 15 October 2013 at 21:37:40 UTC, Namespace wrote: I get this error: /d701/f223.d(11): Error: pure function 'f223.getA' cannot call impure function 'f223.A.~this' with this code: import std.stdio; struct A { public: ~this() { writeln(DTor); } } A getA() pure nothrow { return A(); } void main() { A a = getA(); writeln(end of main); } But without pure and nothrow I get this output: end of main DTor Why the compiler thinks that the function should/could call A::~this? It could have something to do with the fact that RVO is an optimization *opportunity* that the compiler is allowed to go for, even if it changes the program output. Hoewever, being an *opportunity*, the compiler still has to make sure the code is valid without said optimization, which in this case, isn't: getA would destroy it's temporary after blitting it on the stac, leading to an impure call. So it _could_ be impure, but mostly it isn't, right? I guess that's one way to put it. I'd say it *is* impure, but all its impure bits have been optimized out. That's my explanation anyways. I'm curious: Is this a problem for you? The function calling getA *can't* be pure either, so marking getA as pure is ... I was going to say useless, but I guess pure is always an optimization opportunity for the compiler. I'd file an ER, you never know. No, I was just curious what's behind it. So specifically why the compiler could call the destructor. In this case, the created struct literal A() will be moved out to the function getA(). So dtor is not called and compiler should not cause cannot call impure function error. I filed a bug report and posted possible compiler fix. http://d.puremagic.com/issues/show_bug.cgi?id=11286 https://github.com/D-Programming-Language/dmd/pull/2677 Kenji Hara
Re: cannot call impure function ~this
In this case, the created struct literal A() will be moved out to the function getA(). So dtor is not called and compiler should not cause cannot call impure function error. I filed a bug report and posted possible compiler fix. http://d.puremagic.com/issues/show_bug.cgi?id=11286 https://github.com/D-Programming-Language/dmd/pull/2677 Kenji Hara Nice, thank you!
Re: cannot call impure function ~this
On Tuesday, 15 October 2013 at 21:37:40 UTC, Namespace wrote: I get this error: /d701/f223.d(11): Error: pure function 'f223.getA' cannot call impure function 'f223.A.~this' with this code: import std.stdio; struct A { public: ~this() { writeln(DTor); } } A getA() pure nothrow { return A(); } void main() { A a = getA(); writeln(end of main); } But without pure and nothrow I get this output: end of main DTor Why the compiler thinks that the function should/could call A::~this? It could have something to do with the fact that RVO is an optimization *opportunity* that the compiler is allowed to go for, even if it changes the program output. Hoewever, being an *opportunity*, the compiler still has to make sure the code is valid without said optimization, which in this case, isn't: getA would destroy it's temporary after blitting it on the stac, leading to an impure call.
Re: cannot call impure function ~this
On Wednesday, 16 October 2013 at 07:23:45 UTC, monarch_dodra wrote: On Tuesday, 15 October 2013 at 21:37:40 UTC, Namespace wrote: I get this error: /d701/f223.d(11): Error: pure function 'f223.getA' cannot call impure function 'f223.A.~this' with this code: import std.stdio; struct A { public: ~this() { writeln(DTor); } } A getA() pure nothrow { return A(); } void main() { A a = getA(); writeln(end of main); } But without pure and nothrow I get this output: end of main DTor Why the compiler thinks that the function should/could call A::~this? It could have something to do with the fact that RVO is an optimization *opportunity* that the compiler is allowed to go for, even if it changes the program output. Hoewever, being an *opportunity*, the compiler still has to make sure the code is valid without said optimization, which in this case, isn't: getA would destroy it's temporary after blitting it on the stac, leading to an impure call. So it _could_ be impure, but mostly it isn't, right?
Re: cannot call impure function ~this
On Wednesday, 16 October 2013 at 07:27:25 UTC, Namespace wrote: On Wednesday, 16 October 2013 at 07:23:45 UTC, monarch_dodra wrote: On Tuesday, 15 October 2013 at 21:37:40 UTC, Namespace wrote: I get this error: /d701/f223.d(11): Error: pure function 'f223.getA' cannot call impure function 'f223.A.~this' with this code: import std.stdio; struct A { public: ~this() { writeln(DTor); } } A getA() pure nothrow { return A(); } void main() { A a = getA(); writeln(end of main); } But without pure and nothrow I get this output: end of main DTor Why the compiler thinks that the function should/could call A::~this? It could have something to do with the fact that RVO is an optimization *opportunity* that the compiler is allowed to go for, even if it changes the program output. Hoewever, being an *opportunity*, the compiler still has to make sure the code is valid without said optimization, which in this case, isn't: getA would destroy it's temporary after blitting it on the stac, leading to an impure call. So it _could_ be impure, but mostly it isn't, right? I guess that's one way to put it. I'd say it *is* impure, but all its impure bits have been optimized out. That's my explanation anyways. I'm curious: Is this a problem for you? The function calling getA *can't* be pure either, so marking getA as pure is ... I was going to say useless, but I guess pure is always an optimization opportunity for the compiler. I'd file an ER, you never know.
Re: cannot call impure function ~this
On Wednesday, 16 October 2013 at 07:32:27 UTC, monarch_dodra wrote: On Wednesday, 16 October 2013 at 07:27:25 UTC, Namespace wrote: On Wednesday, 16 October 2013 at 07:23:45 UTC, monarch_dodra wrote: On Tuesday, 15 October 2013 at 21:37:40 UTC, Namespace wrote: I get this error: /d701/f223.d(11): Error: pure function 'f223.getA' cannot call impure function 'f223.A.~this' with this code: import std.stdio; struct A { public: ~this() { writeln(DTor); } } A getA() pure nothrow { return A(); } void main() { A a = getA(); writeln(end of main); } But without pure and nothrow I get this output: end of main DTor Why the compiler thinks that the function should/could call A::~this? It could have something to do with the fact that RVO is an optimization *opportunity* that the compiler is allowed to go for, even if it changes the program output. Hoewever, being an *opportunity*, the compiler still has to make sure the code is valid without said optimization, which in this case, isn't: getA would destroy it's temporary after blitting it on the stac, leading to an impure call. So it _could_ be impure, but mostly it isn't, right? I guess that's one way to put it. I'd say it *is* impure, but all its impure bits have been optimized out. That's my explanation anyways. I'm curious: Is this a problem for you? The function calling getA *can't* be pure either, so marking getA as pure is ... I was going to say useless, but I guess pure is always an optimization opportunity for the compiler. I'd file an ER, you never know. No, I was just curious what's behind it. So specifically why the compiler could call the destructor.
cannot call impure function ~this
I get this error: /d701/f223.d(11): Error: pure function 'f223.getA' cannot call impure function 'f223.A.~this' with this code: import std.stdio; struct A { public: ~this() { writeln(DTor); } } A getA() pure nothrow { return A(); } void main() { A a = getA(); writeln(end of main); } But without pure and nothrow I get this output: end of main DTor Why the compiler thinks that the function should/could call A::~this?
Why is to(T) pure but roundTo(T) impure?
Hi -- I've been trying to learn more about D's purity features after reading David Nadlinger's interesting post on this topic. While 'purifying' some existing code I discovered that I can't use roundTo in a pure function, and I don't understand why. Is this a general problem with most floating-point library calls? (e.g. I noticed std.math.floor() is impure as well). import std.conv; int func(double d) pure { // compiles... return to!int(d); } int func2(double d) pure { //doesn't compile!?! return roundTo!int(d); } Thanks for any pointers! -Chris
Re: Why is to(T) pure but roundTo(T) impure?
On Saturday, June 09, 2012 20:43:42 Chris Saunders wrote: Hi -- I've been trying to learn more about D's purity features after reading David Nadlinger's interesting post on this topic. While 'purifying' some existing code I discovered that I can't use roundTo in a pure function, and I don't understand why. Is this a general problem with most floating-point library calls? (e.g. I noticed std.math.floor() is impure as well). import std.conv; int func(double d) pure { // compiles... return to!int(d); } int func2(double d) pure { //doesn't compile!?! return roundTo!int(d); } Thanks for any pointers! One of them ends up calling an impure function and the other doesn't. All it takes is using one low-level function which isn't pure yet, and _boom_, it can't be pure. This currently happens with pretty much any and all string conversions, for instance, primarily because the low-level array stuff (like Appender) can't be pure yet. In the case of to!int, this overload is called T toImpl(T, S)(S value) if (!isImplicitlyConvertible!(S, T) (isNumeric!S || isSomeChar!S) (isNumeric!T || isSomeChar!T)) { enum sSmallest = mostNegative!S; enum tSmallest = mostNegative!T; static if (sSmallest 0) { // possible underflow converting from a signed static if (tSmallest == 0) { immutable good = value = 0; } else { static assert(tSmallest 0); immutable good = value = tSmallest; } if (!good) throw new ConvOverflowException(Conversion negative overflow); } static if (S.max T.max) { // possible overflow if (value T.max) throw new ConvOverflowException(Conversion positive overflow); } return cast(T) value; } Notice the lack of functions being called. The only one is ConvOverflowException's constructor, but apparently that works in a pure function (even though the constructor isn't marked as pure - maybe it's because it's an exception which as being thrown). Whereas, this is roundTo's definition template roundTo(Target) { Target roundTo(Source)(Source value) { static assert(isFloatingPoint!Source); static assert(isIntegral!Target); return to!Target(trunc(value + (value 0 ? -0.5L : 0.5L))); } } Note the call to std.math.trunc. It isn't pure, so voila, roundTo can't be pure. Now, it looks like trunc can't be pure because it's calling a C function, and there's a good chance that the declaration for that C function (core.stdc.math.truncl) can be marked as pure, and then trunc could be marked as pure, and then roundTo could be pure, but that obviously hasn't happened yet. In general, it takes very little for a function to be unable to be pure, especially if it involves low level stuff and/or C stuff in any way. - Jonathan M Davis
Re: Why is to(T) pure but roundTo(T) impure?
On Saturday, 9 June 2012 at 19:33:55 UTC, Jonathan M Davis wrote: On Saturday, June 09, 2012 20:43:42 Chris Saunders wrote: Hi -- I've been trying to learn more about D's purity features after reading David Nadlinger's interesting post on this topic. While 'purifying' some existing code I discovered that I can't use roundTo in a pure function, and I don't understand why. Is this a general problem with most floating-point library calls? (e.g. I noticed std.math.floor() is impure as well). import std.conv; int func(double d) pure { // compiles... return to!int(d); } int func2(double d) pure { //doesn't compile!?! return roundTo!int(d); } Thanks for any pointers! One of them ends up calling an impure function and the other doesn't. All it takes is using one low-level function which isn't pure yet, and _boom_, it can't be pure. This currently happens with pretty much any and all string conversions, for instance, primarily because the low-level array stuff (like Appender) can't be pure yet. In the case of to!int, this overload is called T toImpl(T, S)(S value) if (!isImplicitlyConvertible!(S, T) (isNumeric!S || isSomeChar!S) (isNumeric!T || isSomeChar!T)) { enum sSmallest = mostNegative!S; enum tSmallest = mostNegative!T; static if (sSmallest 0) { // possible underflow converting from a signed static if (tSmallest == 0) { immutable good = value = 0; } else { static assert(tSmallest 0); immutable good = value = tSmallest; } if (!good) throw new ConvOverflowException(Conversion negative overflow); } static if (S.max T.max) { // possible overflow if (value T.max) throw new ConvOverflowException(Conversion positive overflow); } return cast(T) value; } Notice the lack of functions being called. The only one is ConvOverflowException's constructor, but apparently that works in a pure function (even though the constructor isn't marked as pure - maybe it's because it's an exception which as being thrown). Whereas, this is roundTo's definition template roundTo(Target) { Target roundTo(Source)(Source value) { static assert(isFloatingPoint!Source); static assert(isIntegral!Target); return to!Target(trunc(value + (value 0 ? -0.5L : 0.5L))); } } Note the call to std.math.trunc. It isn't pure, so voila, roundTo can't be pure. Now, it looks like trunc can't be pure because it's calling a C function, and there's a good chance that the declaration for that C function (core.stdc.math.truncl) can be marked as pure, and then trunc could be marked as pure, and then roundTo could be pure, but that obviously hasn't happened yet. In general, it takes very little for a function to be unable to be pure, especially if it involves low level stuff and/or C stuff in any way. - Jonathan M Davis Thanks Jonathan. Sounds like a practical issue rather than some theoretical problem -- good to know.
Re: Why is to(T) pure but roundTo(T) impure?
On Sunday, June 10, 2012 04:06:03 Chris Saunders wrote: Thanks Jonathan. Sounds like a practical issue rather than some theoretical problem -- good to know. The vast majority of purity issues with Phobos are purely an implementation issue and not any kind of limit in the language. Obviously some stuff can never be pure (e.g. Clock.currTime or writeln), but for conversions and the like, it's virtually a guarantee that it's an issue with not all of the lower level stuff or C stuff being pure like it needs to be. That's slowly getting fixed, but we still have quite a ways to go. Probably the biggest problem with that from the users perspective is format and to!string, because that makes it almost impossible to make toString pure or to have formatted error messages in assertions in pure functions. We'll get there though. - Jonathan M Davis
Re: pure functions calling impure functions at compile-time
On 23/05/12 11:41, bearophile wrote: Simen Kjaeraas: Should this be filed as a bug, or is the plan that only pure functions be ctfe-able? (or has someone already filed it, perhaps) It's already in Bugzilla, see issue 7994 and 6169. It's just happening because the purity checking is currently being done in a very unsophisticated way. But I think there is a semantic hole in some of the discussions about this problem. Is a future compile-time JIT allowed to perform purity-derived optimizations in CTFE? Some, definitely. Eg. foo(n) + foo(n) can be changed to 2*foo(n), where n is an integer, regardless of what foo does. It does need to be a bit conservative, but I think the issues aren't CTFE specific. Eg, something like this currently gives an assert at runtime: pure nothrow void check(int n) pure nothrow { assert(n == 4); } void main() { check(3); } even though check() can do nothing other than cause an error, it still cannot be optimized away. But you can get rid of all subsequent calls to it, because they'll produce the same error every time.
Re: pure functions calling impure functions at compile-time
Simen Kjaeraas: Should this be filed as a bug, or is the plan that only pure functions be ctfe-able? (or has someone already filed it, perhaps) It's already in Bugzilla, see issue 7994 and 6169. But I think there is a semantic hole in some of the discussions about this problem. Is a future compile-time JIT allowed to perform purity-derived optimizations in CTFE? Bye, bearophile
Re: Why is std.algorithm.reduce impure?
On Wed, 07 Mar 2012 01:41:22 +0100, Jonathan M Davis jmdavisp...@gmx.com wrote: It really takes very little for something to be impure, and optimizations often do it, because they end up using low-level constructs which aren't pure - some of which could be but aren't and others which probably can't be. Just so this is clear - no optimization of the compiler is going to change the purity of a function. An optimization on the part of the programmer (like using appender) might, though.
Re: Why is std.algorithm.reduce impure?
On 03/07/2012 05:29 PM, Simen Kjærås wrote: On Wed, 07 Mar 2012 01:41:22 +0100, Jonathan M Davis jmdavisp...@gmx.com wrote: It really takes very little for something to be impure, and optimizations often do it, because they end up using low-level constructs which aren't pure - some of which could be but aren't and others which probably can't be. Just so this is clear - no optimization of the compiler is going to change the purity of a function. An optimization on the part of the programmer (like using appender) might, though. Appender must become pure.
Re: Why is std.algorithm.reduce impure?
On Wednesday, March 07, 2012 17:58:43 Timon Gehr wrote: On 03/07/2012 05:29 PM, Simen Kjærås wrote: On Wed, 07 Mar 2012 01:41:22 +0100, Jonathan M Davis jmdavisp...@gmx.com wrote: It really takes very little for something to be impure, and optimizations often do it, because they end up using low-level constructs which aren't pure - some of which could be but aren't and others which probably can't be. Just so this is clear - no optimization of the compiler is going to change the purity of a function. An optimization on the part of the programmer (like using appender) might, though. Appender must become pure. Most definitely. A variety of things which are currently impure must become pure. Some things which didn't used to be pure still are, but there's still plenty left that need to be sorted out. - Jonathan M Davis
Re: Why is std.algorithm.reduce impure?
On Wednesday, March 07, 2012 17:29:24 Simen Kjærås wrote: On Wed, 07 Mar 2012 01:41:22 +0100, Jonathan M Davis jmdavisp...@gmx.com wrote: It really takes very little for something to be impure, and optimizations often do it, because they end up using low-level constructs which aren't pure - some of which could be but aren't and others which probably can't be. Just so this is clear - no optimization of the compiler is going to change the purity of a function. An optimization on the part of the programmer (like using appender) might, though. I didn't say that it did, though maybe I wasn't clear enough. Optimizations of the _algorithms_ involved can make a function impure - such as use Appender instead of ~= when building arrays. - Jonathan M Davis
Why is std.algorithm.reduce impure?
Why is std.algorithm.reduce not marked pure? It makes it impossible to do things like this: pure const int product(int[] args) { return reduce!a * b(args); } T -- Life is unfair. Ask too much from it, and it may decide you don't deserve what you have now either.
Re: Why is std.algorithm.reduce impure?
On Tuesday, 6 March 2012 at 22:39:20 UTC, H. S. Teoh wrote: Why is std.algorithm.reduce not marked pure? It doesn't have to be - templates are inferred to be pure or not. If you take the const off that signature, your example works in today's dmd.
Re: Why is std.algorithm.reduce impure?
On Tue, Mar 06, 2012 at 11:42:00PM +0100, Adam D. Ruppe wrote: On Tuesday, 6 March 2012 at 22:39:20 UTC, H. S. Teoh wrote: Why is std.algorithm.reduce not marked pure? It doesn't have to be - templates are inferred to be pure or not. If you take the const off that signature, your example works in today's dmd. Oh? what's wrong with the const? T -- Don't modify spaghetti code unless you can eat the consequences.
Re: Why is std.algorithm.reduce impure?
On Tuesday, 6 March 2012 at 22:48:30 UTC, H. S. Teoh wrote: Oh? what's wrong with the const? test10.d(3): Error: function test10.product without 'this' cannot be const/immutable It works if you put parens on it: pure const(int) product(int[] args) { Without the parenthesis, D wants to apply it to this, like if you write void foo() const {} in C++. The reason here is most the attributes are at the beginning, which is cool because this works: const { void foo() {} int bar() {} } etc. But if you put parens on it, it specifically applies to the int.
Re: Why is std.algorithm.reduce impure?
On Tue, Mar 06, 2012 at 11:51:05PM +0100, Adam D. Ruppe wrote: On Tuesday, 6 March 2012 at 22:48:30 UTC, H. S. Teoh wrote: Oh? what's wrong with the const? test10.d(3): Error: function test10.product without 'this' cannot be const/immutable It works if you put parens on it: pure const(int) product(int[] args) { Without the parenthesis, D wants to apply it to this, like if you write void foo() const {} in C++. But why can't 'this' be const? For example, why does the compiler reject this: class A { int[] data; pure const int sum() { return reduce!a*b(data); } } I'm not modifying data at at all, so why should it be an error? T -- Don't modify spaghetti code unless you can eat the consequences.
Re: Why is std.algorithm.reduce impure?
On Tue, Mar 06, 2012 at 03:00:16PM -0800, H. S. Teoh wrote: [...] But why can't 'this' be const? For example, why does the compiler reject this: class A { int[] data; pure const int sum() { return reduce!a*b(data); } } I'm not modifying data at at all, so why should it be an error? [...] Actually, nevermind that. Looks like a compiler bug that got fixed in dmd, but hasn't been pulled into gdc yet. I'll just have to be patient. :-) T -- A mathematician is a device for turning coffee into theorems. -- P. Erdos
Re: Why is std.algorithm.reduce impure?
On Tuesday, March 06, 2012 14:41:01 H. S. Teoh wrote: Why is std.algorithm.reduce not marked pure? It makes it impossible to do things like this: pure const int product(int[] args) { return reduce!a * b(args); } You'd have to look through the implementation and possibly tweak it to figure it out. All it takes is _one_ thing in there which isn't considered pure, and reduce won't be pure. Glancing at it, I suspect that its use of emplace is the culprit. emplace uses memcpy in some of its overloads, and memcpy probably isn't marked as pure, since it's a C function. It theoretically _could_ be marked as pure - and arguably should be - but I very much doubt that it is right now. It really takes very little for something to be impure, and optimizations often do it, because they end up using low-level constructs which aren't pure - some of which could be but aren't and others which probably can't be. More effort needs to be made in sorting out the purity of a number of the low-level constructs. Appender, for instance, screws up a lot of the string stuff, because it isn't pure. And it's far from the sole culprit. - Jonathan M Davis
Re: Why is std.algorithm.reduce impure?
H. S. Teoh: But why can't 'this' be const? For example, why does the compiler reject this: class A { int[] data; pure const int sum() { return reduce!a*b(data); } } I'm not modifying data at at all, so why should it be an error? I think it's a small bug in std.algorithm.reduce, is this in Bugzilla already? import std.algorithm: reduce; void main() { const data = [2, 3, 4]; int r1 = reduce!q{a * b}(0, data); // OK int r2 = reduce!q{a * b}(data); } In std.algorithm.reduce there is also this (now bug 2443 is fixed) at about line 723: // For now, just iterate using ref to avoid unnecessary copying. // When Bug 2443 is fixed, this may need to change. foreach(ref elem; r) { if(initialized) Bye, bearophile
Impure static
This little D2 program, a pure function contains static variables initialized with calls to not pure functions: int foo() { return 1; } pure int bar() { enum int x1 = foo(); static immutable int x2 = foo(); return x1; } void main() {} The latest DMD gives: test.d(5): Error: pure function 'bar' cannot call impure function 'foo' test.d(5):called from here: foo() test.d(5):called from here: foo() test.d(6): Error: pure function 'bar' cannot call impure function 'foo' test.d(6):called from here: foo() test.d(6):called from here: foo() I think I asked a similar question in past, is it right to expect DMD to compile this program? Bye and thank you, bearophile
Re: Impure static
On 11/09/2011 02:16 PM, bearophile wrote: This little D2 program, a pure function contains static variables initialized with calls to not pure functions: int foo() { return 1; } pure int bar() { enum int x1 = foo(); static immutable int x2 = foo(); return x1; } void main() {} The latest DMD gives: test.d(5): Error: pure function 'bar' cannot call impure function 'foo' test.d(5):called from here: foo() test.d(5):called from here: foo() test.d(6): Error: pure function 'bar' cannot call impure function 'foo' test.d(6):called from here: foo() test.d(6):called from here: foo() I think I asked a similar question in past, is it right to expect DMD to compile this program? Yes. Here is the bug report: http://d.puremagic.com/issues/show_bug.cgi?id=6169