Re: Software validation
On Monday, 4 June 2018 at 15:48:35 UTC, DigitalDesigns wrote: Just curious if something exists that allows for mathematical validation such code in an relatively canonical way. This isn't too hard for pure functions but dealing with non-pure functions can be a pain. Something like HACL? https://github.com/mitls/hacl-c
Can anyone explain this?
I set up to find out what happens if the assert string throws. I have to admit I did not expect the result: $ cat test.d import std.stdio; import core.exception; void main() { scope(failure) { writeln("Not gonna happen"); } try { static string throwingFunc() { throw new Exception("An exception"); } assert(0==1, throwingFunc()); } catch(Exception ex) { writeln("Exception"); } catch(AssertError ex) { writeln("Assert"); } } $ ldc2 --version LDC - the LLVM D compiler (1.8.0): based on DMD v2.078.3 and LLVM 5.0.1 ... $ ./test Not gonna happen object.Exception@test.d(11): An exception ??:? [0x3728941e] ??:? [0x372903aa] ??:? [0x3727b15c] ??:? [0x3724991d] ??:? [0x372496c9] ??:? [0x3727aecf] ??:? [0x3727addb] ??:? [0x3724a124] ??:? __libc_start_main [0xed8b01c0] ??:? [0x372495c9] $ dmd --version DMD64 D Compiler v2.080.0 Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved written by Walter Bright $ ./test Not gonna happen object.Exception@test.d(11): An exception ??:? pure @safe immutable(char)[] test.main().throwingFunc() [0xe9b1c2b3] ??:? _Dmain [0xe9b1c1ad]
Re: Software validation
On Tuesday, 5 June 2018 at 06:45:31 UTC, Petar Kirov [ZombineDev] wrote: On Monday, 4 June 2018 at 15:48:35 UTC, DigitalDesigns wrote: Does D have any methods of validating code in a natural manner besides unit tests and contracts? I'm specifically thinking of validating mathematical calculations and boolean operations that could depend on very improbable scenarios but are technically invalid logic. These issues tend to creep up in calculations that involve floating points due to various reasons or comparisons that mistakenly use > for >= or vice versa. If I have a variable such as a buffer which has a length and an offset in to that buffer is calculated using double precision then rounding errors could cause the offset to except the length and create an access violation. To be able to theoretically test all the possibilities all valid inputs would need to be checked. One can setup unit tests to test these possibilities but it can be difficult to cover all cases in even a semi-complex program. Just curious if something exists that allows for mathematical validation such code in an relatively canonical way. This isn't too hard for pure functions but dealing with non-pure functions can be a pain. Perhaps not quite what you're looking for, but I think you would be interested in the LLVM fuzzing part of Johan Engelen's talk at DConf 2018: https://www.youtube.com/watch?v=GMKvYrjaaoU (at around 34:30). Sorta, but not fuzzing because that is too spare. Rather than picking a random point in a billion dimensional vector space bit is sort of works only on the surface of possible values. Which he addresses initially being the problem and is similar to what I'm looking for. The idea though is problems almost always occur on edge cases so there is no need to check everything inside an interval but only the edge cases. if (x < 10) one only needs to check if x = 9, 10, 11 but not 4, 5, etc. Of course, in more complex cases it might be difficult to determine this so maybe the method in the video is more general purpose. It seems to have the capabilities to have a bit more intelligent checking though so yeah, this seems to be what I was looking for! Thanks! In any case
Re: Can anyone explain this?
On Tuesday, 5 June 2018 at 08:12:54 UTC, Shachar Shemesh wrote: I set up to find out what happens if the assert string throws. I have to admit I did not expect the result: $ cat test.d import std.stdio; import core.exception; void main() { scope(failure) { writeln("Not gonna happen"); } try { static string throwingFunc() { throw new Exception("An exception"); } assert(0==1, throwingFunc()); } catch(Exception ex) { writeln("Exception"); } catch(AssertError ex) { writeln("Assert"); } } $ ldc2 --version LDC - the LLVM D compiler (1.8.0): based on DMD v2.078.3 and LLVM 5.0.1 ... $ ./test Not gonna happen object.Exception@test.d(11): An exception applying a bit of lowering int Dmain (int arc, const char** argv) { try return main(); catch (...) dumpThrowable(); // 3 dumps exception } void main() { try { try { static string throwingFunc() { throw new Exception("An exception"); } __assert_fail(throwingFunc(),...); // 1 throws before assert throws } catch(Exception ex) { writeln("Exception"); // Why is this not caught? I've no idea } catch(AssertError ex) { writeln("Assert"); // this is not caught because the thrown throwable is not an exception } } catch(...) { writeln("Not gonna happen"); // 2 scope failure is run throw; } }
Re: Can anyone explain this?
On Tuesday, 5 June 2018 at 08:12:54 UTC, Shachar Shemesh wrote: I set up to find out what happens if the assert string throws. From here: https://dlang.org/spec/expression.html#assert_expressions [...] 8. Undefined Behavior: Once in an Invalid State the behavior of the continuing execution of the program is undefined. [...] [...] Best Practices: - Do not have side effects in either AssignExpression that subsequent code depends on. - AssertExpressions are intended to detect bugs in the program, do not use for detecting input or environmental errors. - Do not attempt to resume normal execution after an Assert Failure. [...] Anyway you can try to catch "Throwable" to understand what is going to happen (but it's not a good idea at all to keep it in a program) Andrea
Re: Can anyone explain this?
On 05/06/18 11:26, Nicholas Wilson wrote: writeln("Exception"); // Why is this not caught? I've no idea That's the part I was referring to.
Re: Can anyone explain this?
On Tuesday, 5 June 2018 at 08:26:22 UTC, Nicholas Wilson wrote: writeln("Assert"); // this is not caught because the thrown throwable is not an exception Now that's plain false - If you replace the call to throwingFunc() with a string literal, you'll see it's properly caught. Also, the catch clause explicitly specifies AssertError, which as the name implies, is an Error, not an Exception. This might just be a case of undefined behavior. According to https://dlang.org/spec/contracts.html: "As a contract, an assert represents a guarantee that the code must uphold. Any failure of this expression represents a logic error in the code that must be fixed in the source code. A program for which the assert contract is false is, by definition, invalid, and therefore has undefined behaviour." In short, what you're doing is UB, and the nasal demons are printing 'not gonna happen' to your console. That also makes some sense with Andrea Fontana's comments: - Do not have side effects in either AssignExpression that subsequent code depends on. - Do not attempt to resume normal execution after an Assert Failure. However, if we add catch (Throwable ex) to the list of catch statements, that *does* catch a regular object.Exception. Moving the catch (Exception) statement down the list does nothing. Adding another layer of try-catch also catches it (even with just catch (Exception ex)): import std.stdio; import core.exception; unittest { scope(failure) { writeln("Not gonna happen"); } try { try { static string throwingFunc() { throw new Exception("An exception"); } assert(0==1, throwingFunc()); } catch(AssertError ex) { writeln("Assert"); } catch(Exception ex) { writeln("Exception A"); } } catch(Exception ex) { writeln("Exception B"); } } So I'm stumped. It seems the exception handling is simply not setup correctly. This could be because of UB I guess, but I'd hope the AssertError would be thrown first in such a case. -- Simen
Re: Can anyone explain this?
On Tuesday, 5 June 2018 at 09:03:03 UTC, Simen Kjærås wrote: On Tuesday, 5 June 2018 at 08:26:22 UTC, Nicholas Wilson wrote: writeln("Assert"); // this is not caught because the thrown throwable is not an exception Now that's plain false - If you replace the call to throwingFunc() with a string literal, you'll see it's properly caught. Also, the catch clause explicitly specifies AssertError, which as the name implies, is an Error, not an Exception. Whoops I meant _is_. However, if we add catch (Throwable ex) to the list of catch statements, that *does* catch a regular object.Exception. Moving the catch (Exception) statement down the list does nothing. Adding another layer of try-catch also catches it (even with just catch (Exception ex)): That does seem odd but is consistent with the implicit "try" surrounding Dmain inserted by the runtime. import std.stdio; import core.exception; unittest { scope(failure) { writeln("Not gonna happen"); } try { try { static string throwingFunc() { throw new Exception("An exception"); } assert(0==1, throwingFunc()); } catch(AssertError ex) { writeln("Assert"); } catch(Exception ex) { writeln("Exception A"); } } catch(Exception ex) { writeln("Exception B"); } } So I'm stumped. It seems the exception handling is simply not setup correctly. This could be because of UB I guess, but I'd hope the AssertError would be thrown first in such a case. The assert error will never be thrown because one of the parameters to the __assert_fail throws. Its like as if you had written. if (0==1) { string tmp = throwingFunc(); // throws __assert_fail(tmp,__LINE__,...); // dead code. } Actually it may be the compiler doing something funky with assert(0, msg); being special (assert(0,...) since the spec says for assert any compile time expression == 0 has the effect of assert(0). i.e. assert(0==1); is the same as assert(0);). Proof import std.stdio; import core.exception; bool foo() { return false;} // mess with the compiler's reasoning about the truthiness of the assert void main() { scope(failure) { writeln("Not gonna happen"); } try { static string throwingFunc() { throw new Exception("An exception"); } assert(foo(), throwingFunc()); } catch(Exception ex) { writeln("Exception"); } catch(AssertError ex) { writeln("Assert"); } } prints Exception
Mixin templates are a pain at best, useless at worst for any non-trivial use case
I've come across this before with Binderoo, but now I've got really simple use cases. Rather than having one unmaintainable mess of a file that handles everything (for a really egregious example, see std.datetime.systime which has the distinction of both its source code and documentation being unreadable), I decided to do something similar to C#'s partial classes and use mixin templates declared in other modules to complete the implementation. This is all well and good until you get to dealing with function overloads. Exhibit A: https://run.dlang.io/is/a85Lbq As soon as you have an overload of a function declared in the base object you're mixing in to, any other overload mixed in will not resolve correctly. Great. The core use case I derived this from is client/server message handling, and I plan on reusing mixins across client/server types since message handling will also require variables added in to the object to do so. Simple example: Handling Ping and Pong will require the Ping sender to start a timer and resolve it on receiving Pong. The partial class model is perfect for this, and mixins are the closest we have to this. I submitted a bug with the above code, and it was "helpfully" shut down with a link to the documentation and workaround. Congratulations. That's not the use case here, and to be quite honest this is one of those examples where a #define macro would "just work". And I'm firmly of the view that *ANY* example of that should be dealt with at a language level in order to completely remove the argument of needing a preprocessor. Exhibit B: https://run.dlang.io/is/s2BJUO This one fired as soon as Binderoo tried to do its thing: Doing an allMembers pass of the object will list your entirely-mixed-in overload as a member, but attempting to get that member will resolve the symbol to void. Great. So functions that otherwise completely resolve as a member of a class actually don't resolve as a member of a class? Huh? I don't even. To see where I'm going with this, exhibit C: https://run.dlang.io/is/KWN9yA Rather than mixin things one by one and manually handle errors and language shortcomings, I'm using helpers to wholesale add functionality to my object. And, honestly, with this method, I am already seeing the workaround. Because I've had to do it a ton of times already with other templates. Run a search for 'mixin( "import' in Binderoo to see how many times I've had to get around the changes to template visibility rules. Rather than do that though, now I'll have to iterate over every member of a stored mixin and alias them in to the surrounding object. Sigh. I know that simply posting this will result in a thread of people offering workarounds. I don't need or want them. Why? Because the next person that tries to do this will have the same problems. And rather than the "correct" way to do this be voodoo knowledge found by a Google search if you're lucky, I would far prefer this thread become a discussion on how to improve mixins so that a DIP can be written and resolved. So that the next person can express language as simply as possible and have it all Just Work(TM).
Re: Mixin templates are a pain at best, useless at worst for any non-trivial use case
On Tuesday, 5 June 2018 at 10:11:49 UTC, Ethan wrote: Exhibit A: https://run.dlang.io/is/a85Lbq [..snip..] I submitted a bug with the above code, and it was "helpfully" shut down with a link to the documentation and workaround. This looks like the bug report you are referring to: https://issues.dlang.org/show_bug.cgi?id=18944 I understand that the specification defines the current behavior and provides a workaround, but what's the justification for that behavior? Is it hygiene? I've been interested in improving mixins for reasons discussed in the interpolated strings PR (https://github.com/dlang/dmd/pull/7988) and this discussion about library-implemented properties (https://forum.dlang.org/post/mqveusvzkmkshrzws...@forum.dlang.org). Perhaps there's an opportunity here for a language improvement that would help all of these use cases. Mike
Re: Mixin templates are a pain at best, useless at worst for any non-trivial use case
On Tuesday, 5 June 2018 at 10:11:49 UTC, Ethan wrote: And, honestly, with this method, I am already seeing the workaround. Because I've had to do it a ton of times already with other templates. Run a search for 'mixin( "import' in Binderoo to see how many times I've had to get around the changes to template visibility rules. Rather than do that though, now I'll have to iterate over every member of a stored mixin and alias them in to the surrounding object. I've had to go nuclear, in fact, to get this working. And resort to string mixins. https://run.dlang.io/is/O5PDaK So it works. But it doesn't Just Work(TM).
Re: Mixin templates are a pain at best, useless at worst for any non-trivial use case
On Tuesday, 5 June 2018 at 10:11:49 UTC, Ethan wrote: Exhibit A: https://run.dlang.io/is/a85Lbq I submitted a bug with the above code, and it was "helpfully" shut down with a link to the documentation and workaround. Congratulations. That's not the use case here, and to be quite honest this is one of those examples where a #define macro would "just work". And I'm firmly of the view that *ANY* example of that should be dealt with at a language level in order to completely remove the argument of needing a preprocessor. There's a reason for those rules in the language, namely function hijacking. This is an issue we take very seriously, and workarounds exists. As you point out, the suggested workaround is aliasing each function in the mixin (you also say you don't want workarounds - bear with me, I'm building to a point). This can to some extent be encapsulated in a string mixin that's used alongside any template mixin: string introduceSymbols(alias F)() { enum id = __traits(identifier, F); return "static foreach (fn; __traits(allMembers, "~id~")) {"~ "mixin(`alias `~fn~` = "~id~".`~fn~`;`);"~ "}"; } mixin foo!() foo_; mixin(introduceSymbols!foo_); This introduces complexity in that each mixin must be given a unique name at instantiation, another line must be included with every mixin, and the name must be repeated in the second line. This situation is less than optimal, and the compiler gives no help if you've forgotten a introduceSymbols line, or passed it the wrong name. These issues can be ameliorated as in your other post here, by wrapping the template mixin statement as well. This leads to a host of other problems - how do you specify arguments to the mixin template? How do you deal with aliased mixin templates? These issues may possibly be fixed, but it's gonna get ugly. Can we perhaps do better? Could we somehow say at the instantiation point 'please introduce all symbols in this mixin into the instantiation scope even if there are hijackings.'? Something like `mixin scope foo!();`? That seems possible to me. If we write a DIP for it, I've a good feeling about getting that into the language. This issue shows up every now and then, so we know it's a real issue, and the workarounds are clunky. At the same time, the current behavior is there for a reason, and is very unlikely to change. -- Simen
Re: Can anyone explain this?
On Tuesday, 5 June 2018 at 09:58:43 UTC, Nicholas Wilson wrote: prints Exception https://issues.dlang.org/show_bug.cgi?id=18946
Re: stride in slices
On 6/4/18 5:52 PM, DigitalDesigns wrote: On Monday, 4 June 2018 at 17:40:57 UTC, Dennis wrote: On Monday, 4 June 2018 at 15:43:20 UTC, Steven Schveighoffer wrote: Note, it's not going to necessarily be as efficient, but it's likely to be close. -Steve I've compared the range versions with a for-loop. For integers and longs or high stride amounts the time is roughly equal, but for bytes with low stride amounts it can be up to twice as slow. https://run.dlang.io/is/BoTflQ 50 Mb array, type = byte, stride = 3, compiler = LDC -O4 -release For-loop 18 ms Fill(0) 33 ms each! 33 ms With stride = 13: For-loop 7.3 ms Fill(0) 7.5 ms each! 7.8 ms This is why I wanted to make sure! I would be using it for a stride of 2 and it seems it might have doubled the cost for no other reason than using ranged. Ranges are great but one can't reason about what is happening in then as easy as a direct loop so I wanted to be sure. Thanks for running the test! See later postings from Ethan and others. It's a matter of optimization being able to see the "whole thing". This is why for loops are sometimes better. It's not inherent with ranges, but if you use the right optimization flags, it's done as fast as if you hand-wrote it. What I've found with D (and especially LDC) is that when you give the compiler everything to work with, it can do some seemingly magic things. -Steve
Re: Simple tutorials for complex subjects
On Sunday, 3 June 2018 at 16:25:29 UTC, Ethan wrote: Step seven: In your receive function that takes a byte stream, put in a switch statement that looks a little bit like the following: switch( msg.GetID ) { static foreach( Message; ServerMessages ) { case ObjectIDOf!Message: Message deserialised = msg.FromBinary!Message; this.receive( deserialised ); } default: break; } Why message detection is in receiver instead of infrastructure? And why not gather message types from receiver's interface with DbI (like WCF does)?
Re: stride in slices
On 06/04/2018 07:08 PM, Ethan wrote: On Monday, 4 June 2018 at 18:11:47 UTC, Steven Schveighoffer wrote: BTW, do you have cross-module inlining on? Just to drive this point home. https://run.dlang.io/is/nrdzb0 Manually implemented stride and fill with everything forced inline. Otherwise, the original code is unchanged. 17 ms, 891 μs, and 6 hnsecs 15 ms, 694 μs, and 1 hnsec 15 ms, 570 μs, and 9 hnsecs My new stride outperformed std.range stride, and the manual for-loop. And, because the third test uses the new stride, it also benefited. But interestingly runs every so slightly faster... BTW I've had this thought for a long time to implement stride with a compile-time step... never got around to implementing it. It would easily generalize the existing code without too much work. Essentially the step would be a template parameter; if that is 0, then use a run-time stride. Most of the code works unchanged.
Re: Mixin templates are a pain at best, useless at worst for any non-trivial use case
On Tuesday, 5 June 2018 at 10:11:49 UTC, Ethan wrote: As soon as you have an overload of a function declared in the base object you're mixing in to, any other overload mixed in will not resolve correctly. Great. Yes, it is great, since this lets you selectively override behavior from a generic mixin template for a specific use. I like this. But we might be able to change the rule so, for functions, it follows the overload rules with arguments instead of just going by name. That would let you add functions... but that's inconsistent with how D does child class inheritance too (you need to alias in overloads there as well), for better or for worse. Perhaps adding something like `alias * = Base.*;` as a feature would be good. I kinda hate that. But the idea there would be to just add all of Base's things to the overload set. OK that basically sucks especially when there's multiple bases. but it would be fairly consistent.
pure functions cannot be removed, actually: pure vs. total
I'm just posting to clear up the misunderstanding that a call to a pure function can be removed. Actually, even calls to strongly pure functions cannot always be removed. This is because there is one thing that a pure function can do that will change program behavior if it is removed, even if it does not change any global state whatsoever: it can simply never return. void foo() pure { while (true) { } } By the way, this led to an amusing Phobos bug involving a pure function (not) returning a struct with an enum member: https://github.com/dlang/dmd/pull/8013#pullrequestreview-110250441 and assert(false.repeat.any == true); :) When a strongly pure function is called multiple times with the same parameter, all but the first call can be removed; this is because if it was going to not return, it would already have inf-looped the first time. pure lets you go from n to 1, but not from 1 to 0. A pure function that returns a value for every possible parameter is called a total function. Unfortunately, there is no way to enforce totality in the compiler, due to the halting problem.
Re: D on top of Hacker News!
On Sunday, 3 June 2018 at 17:40:46 UTC, I love Ice Cream wrote: Is D really a top 20 language? I don't remember seeing it anywhere close to the top 20. https://www.tiobe.com/tiobe-index/ has them in 31 Top comment is kind of depressing. The right place to look is https://www.tiobe.com/tiobe-index/d/ I agree with other comments regarding TIOBE - they are constantly changing how they do statistics so they are not relevant source at all. Just look where Kotlin is there and that should pretty much tell you everything. I know at least 10 large companies that are moving from Java/Scala to Kotlin, yet Kotlin is at the bottom 50 table... Ridiculous...
Re: Mixin templates are a pain at best, useless at worst for any non-trivial use case
On Tuesday, 5 June 2018 at 11:35:10 UTC, Ethan wrote: On Tuesday, 5 June 2018 at 10:11:49 UTC, Ethan wrote: And, honestly, with this method, I am already seeing the workaround. Because I've had to do it a ton of times already with other templates. Run a search for 'mixin( "import' in Binderoo to see how many times I've had to get around the changes to template visibility rules. Rather than do that though, now I'll have to iterate over every member of a stored mixin and alias them in to the surrounding object. I've had to go nuclear, in fact, to get this working. And resort to string mixins. https://run.dlang.io/is/O5PDaK So it works. But it doesn't Just Work(TM). avoid unrolling for-each mate. you do that by enclosing the Tuple Argument in [Args].
Re: stride in slices
On Tuesday, 5 June 2018 at 13:05:56 UTC, Steven Schveighoffer wrote: On 6/4/18 5:52 PM, DigitalDesigns wrote: On Monday, 4 June 2018 at 17:40:57 UTC, Dennis wrote: On Monday, 4 June 2018 at 15:43:20 UTC, Steven Schveighoffer wrote: Note, it's not going to necessarily be as efficient, but it's likely to be close. -Steve I've compared the range versions with a for-loop. For integers and longs or high stride amounts the time is roughly equal, but for bytes with low stride amounts it can be up to twice as slow. https://run.dlang.io/is/BoTflQ 50 Mb array, type = byte, stride = 3, compiler = LDC -O4 -release For-loop 18 ms Fill(0) 33 ms each! 33 ms With stride = 13: For-loop 7.3 ms Fill(0) 7.5 ms each! 7.8 ms This is why I wanted to make sure! I would be using it for a stride of 2 and it seems it might have doubled the cost for no other reason than using ranged. Ranges are great but one can't reason about what is happening in then as easy as a direct loop so I wanted to be sure. Thanks for running the test! See later postings from Ethan and others. It's a matter of optimization being able to see the "whole thing". This is why for loops are sometimes better. It's not inherent with ranges, but if you use the right optimization flags, it's done as fast as if you hand-wrote it. What I've found with D (and especially LDC) is that when you give the compiler everything to work with, it can do some seemingly magic things. -Steve It would be nice if testing could be done. Maybe even profiling in unit tests to make sure ranges are within some margin of error(10%). One of the main reasons I don't use ranges is I simply don't have faith they will be as fast as direct encoding. While they might offer a slightly easier syntax I don't know what is going on under the hood so I can't reason about it(unless I look up the source). With a for loop, it is pretty much a wrapper on internal cpu logic so it will be near as fast as possible. I suppose in the long run ranges do have the potential to out perform since they do abstract but there is no guarantee they will even come close. Having some "proof" that they are working well would ease my mind. As this thread shows, ranges have some major issues. Imagine having some code on your machine that is very performant but on another machine in a slightly different circumstances it runs poorly. Now, say it is the stride issue... One normally would not think of that being an issue so one will look in other areas and could waste times. At least with direct loops you pretty much get what you see. It is very easy for ranges to be slow but more difficult for them to be fast.
Re: pure functions cannot be removed, actually: pure vs. total
On Tuesday, 5 June 2018 at 14:48:23 UTC, FeepingCreature wrote: I'm just posting to clear up the misunderstanding that a call to a pure function can be removed. Actually, even calls to strongly pure functions cannot always be removed. This is because there is one thing that a pure function can do that will change program behavior if it is removed, even if it does not change any global state whatsoever: it can simply never return. [...] In that instance you can have false negatives. catgorizing total functions an non total. But no false positives afaics.
Re: Simple tutorials for complex subjects
On Tuesday, 5 June 2018 at 13:33:18 UTC, Kagamin wrote: Why message detection is in receiver instead of infrastructure? Because recursion. One of the messages I've written is a wrapper message for a multi-packet split message, and calls receive with the reconstructed byte buffer. Fairly elegant way to not special-case the thing that much. And why not gather message types from receiver's interface with DbI (like WCF does)? There already is design by introspection. But I don't parse a type, I parse an entire module. The switch statement is being built through the results of an introspective pass. This is quite deliberate. I'm writing a large-scale maintainable codebase. Having everything in one file is a sure way to reduce maintainability and thus productivity of the programmers maintaining it. Getting D to favour lots of smaller files means getting creative. I *could* put all the messages in an interface and inherit from it... but that's a fairly old-school way of thinking. I don't need a giant virtual function table to enforce implementing message types when I can use outside-the-box introspective tricks and compile down to nothing. There's also a design advantage to going message-first here. I'm forcing the maintainers to think of the data before they get to implementation. The existence of a struct already explicitly creates one piece of data - the message ID. Anything else you put in there is up to you. And being structs, means that you don't constantly have to maintain function signatures each time you want to add a value to a message for example.
Re: pure functions cannot be removed, actually: pure vs. total
On 6/5/18 10:48 AM, FeepingCreature wrote: I'm just posting to clear up the misunderstanding that a call to a pure function can be removed. Actually, even calls to strongly pure functions cannot always be removed. This is because there is one thing that a pure function can do that will change program behavior if it is removed, even if it does not change any global state whatsoever: it can simply never return. void foo() pure { while (true) { } } By the way, this led to an amusing Phobos bug involving a pure function (not) returning a struct with an enum member: https://github.com/dlang/dmd/pull/8013#pullrequestreview-110250441 and assert(false.repeat.any == true); :) When a strongly pure function is called multiple times with the same parameter, all but the first call can be removed; this is because if it was going to not return, it would already have inf-looped the first time. pure lets you go from n to 1, but not from 1 to 0. A pure function that returns a value for every possible parameter is called a total function. Unfortunately, there is no way to enforce totality in the compiler, due to the halting problem. I'll repeat what I said in the PR where you made this similar comment, I don't think it is important to ensure a pure function that never returns is always called. Can you explain the benefit of such a thing? We've all heard of optimizers that reduce "code that does nothing" down to just a return statement, foiling people who are expecting benchmarks to run properly, why is this any different? I'm asking because it seems like we give up a really easy optimization for pure functions for the sake of pure infinite loop programs, which I suppose have some value, but not much value. Getting around the infinite loop elision would be pretty simple, just return an int. On the flip side, if the compiler can figure out via introspection that some template function is strong pure and returns void, therefore it doesn't need to call it, that's a much bigger win than preserving the possible infinite loopiness that likely is a bug anyway. Another observation: under the "infinite loops are important observable behavior" world-view, pure functions cannot be lazily evaluated either: pure int foo() { /*infinite loop */} void main(string[] args) { auto a = foo; writeln("hi"); if(args[1] == "printa") writeln(a); } With some optimizers, this can be rewritten: writeln("hi"); if(args[1] == "printa") writeln(foo); Which if foo is a *normally returning* function and not an infinite loop one, then this can save cycles in certain cases. But under your world-view, the optimization is invalid, because foo might have an infinite loop, and then the observable behavior changes (instead of printing nothing and infinite looping, "hi" is printed, and infinite loops). -Steve
Re: stride in slices
On 6/5/18 12:50 PM, DigitalDesigns wrote: I suppose in the long run ranges do have the potential to out perform since they do abstract but there is no guarantee they will even come close. Having some "proof" that they are working well would ease my mind. As this thread shows, ranges have some major issues. Just to point it out again, Ethan's numbers: 17 ms, 891 μs, and 6 hnsecs // for loop 15 ms, 694 μs, and 1 hnsec // fill 15 ms, 570 μs, and 9 hnsecs // each I think ranges are doing just fine. You just need the cross-module inlining turned on. Imagine having some code on your machine that is very performant but on another machine in a slightly different circumstances it runs poorly. Now, say it is the stride issue... One normally would not think of that being an issue so one will look in other areas and could waste times. At least with direct loops you pretty much get what you see. It is very easy for ranges to be slow but more difficult for them to be fast. The same can be said even with direct loops. There are no guarantees of course that one type of programming style is going to outperform another on all platforms and all compilers. My experience is that things that seem like they should be slower can sometimes be faster, and vice versa. It depends on so many factors, and the best thing to do is test and observe in each situation. -Steve
Re: stride in slices
On 05.06.2018 18:50, DigitalDesigns wrote: With a for loop, it is pretty much a wrapper on internal cpu logic so it will be near as fast as possible. This is not even close to being true for modern CPUs. There are a lot of architectural and micro-architectural details that affect performance but are not visible or accessible in your for loop. If you care about performance, you will need to test anyway, as even rather sophisticated models of CPU performance don't get everything right. Also, it is often not necessary to be "as fast as possible". It is usually more helpful to figure out where the bottleneck is for your code and concentrate optimization effort there, which you can do more effectively if you can save time and effort for the remaining parts of your program by writing simple and obviously correct range-based code, which often will be fast as well.
Re: stride in slices
On Tuesday, 5 June 2018 at 18:46:41 UTC, Timon Gehr wrote: On 05.06.2018 18:50, DigitalDesigns wrote: With a for loop, it is pretty much a wrapper on internal cpu logic so it will be near as fast as possible. This is not even close to being true for modern CPUs. There are a lot of architectural and micro-architectural details that affect performance but are not visible or accessible in your for loop. If you care about performance, you will need to test anyway, as even rather sophisticated models of CPU performance don't get everything right. Those optimizations are not part of the instruction set so are irrelevant. They will occur with ranges too. For loops HAVE a direct cpu semantic! Do you doubt this? Cpu's do not have range semantics. Ranges are layers on top of compiler semantics... you act like they are equivalent, they are not! All range semantics must go through the library code then to the compiler then to cpu. For loops of all major systems languages go almost directly to cpu instructions. for(int i = 0; i < N; i++) translates in to either increment and loop or jump instructions. There is absolutely no reason why any decent compiler would not use what the cpu has to offer. For loops are language semantics, Ranges are library semantics. To pretend they are equivalent is wrong and no amount of justifying will make them the same. I actually do not know even any commercial viable cpu exists without loop semantics. I also no of no commercially viable compiler that does not wrap those instructions in a for loop(or while, or whatever) like syntax that almost maps directly to the cpu instructions. Also, it is often not necessary to be "as fast as possible". It is usually more helpful to figure out where the bottleneck is for your code and concentrate optimization effort there, which you can do more effectively if you can save time and effort for the remaining parts of your program by writing simple and obviously correct range-based code, which often will be fast as well. It's also often not necessary to be "as slow as possible". I'm not asking for about generalities but specifics. It's great to make generalizations about how things should be but I would like to know how they are. Maybe in theory ranges could be more optimal than other semantics but theory never equals practice.
Re: stride in slices
On Tuesday, 5 June 2018 at 19:05:27 UTC, DigitalDesigns wrote: For loops HAVE a direct cpu semantic! Do you doubt this? What are they? And for bonus points, are they actually used by compilers? Then the final question: is the generated code any different than inlined ranges?
Re: stride in slices
On 6/5/18 3:05 PM, DigitalDesigns wrote: It's also often not necessary to be "as slow as possible". I'm not asking for about generalities but specifics. It's great to make generalizations about how things should be but I would like to know how they are. Maybe in theory ranges could be more optimal than other semantics but theory never equals practice. Again, I want to stress, ranges are not "as slow as possible", and it's clear from the numbers posted here that they are faster than for loops in practice, at least for this example. -Steve
Re: stride in slices
On Tuesday, 5 June 2018 at 19:05:27 UTC, DigitalDesigns wrote: For loops HAVE a direct cpu semantic! Do you doubt this? ... Right. If you're gonna keep running your mouth off. How about looking at some disassembly then. for(auto i=0; iUsing ldc -O4 -release for x86_64 processors, the initialiser translates to: mov byte ptr [rbp + rcx], 0 The comparison translates to: cmp r13, rcx ja .LBB0_2 And the increment and store translates to: mov byte ptr [rbp + rcx], 0 movsxd rcx, eax add eax, 3 So. It uses three of the most basic instructions you can think of: mov, cmp, j, add. Now, what might you ask are the instructions that a range compiles down to when everything is properly inlined? The initialisation, since it's a function, pulls from the stack. mov rax, qword ptr [rsp + 16] movsxd rcx, dword ptr [rsp + 32] But the comparison looks virtually identical. cmp rax, rcx jb .LBB2_4 But how does it do the add? With some register magic. movsxd rcx, edx lea edx, [rcx + r9] Now, what that looks like it's doing to me is combing the pointer load and index increment in to two those two instructions. One instruction less than the flat for loop. In conclusion. The semantics you talk about are literally some of the most basic instructions in computing; and that escaping the confines of a for loop for a foreach loop can let the compiler generate more efficient code than 50-year-old compsci concepts can.
Re: D on top of Hacker News!
On Tuesday, June 05, 2018 15:09:56 Dejan Lekic via Digitalmars-d wrote: > On Sunday, 3 June 2018 at 17:40:46 UTC, I love Ice Cream wrote: > >> Is D really a top 20 language? I don't remember seeing it > >> anywhere close to the top 20. > >> > >> https://www.tiobe.com/tiobe-index/ has them in 31 > > > > Top comment is kind of depressing. > > The right place to look is https://www.tiobe.com/tiobe-index/d/ > > I agree with other comments regarding TIOBE - they are constantly > changing how they do statistics so they are not relevant source > at all. Just look where Kotlin is there and that should pretty > much tell you everything. I know at least 10 large companies that > are moving from Java/Scala to Kotlin, yet Kotlin is at the bottom > 50 table... Ridiculous... The TIOBE has never been a measurement of how much any given language is used. At best, it's been a measurement of which languages folks have been searching for. That can tell you something, but you have to understand what it's measuring to have any clue what it does tell you. And of course, because of how difficult it is to measure search results for a particular language, they keep changing their criteria. The result is that while the tiobe index may be interesting, it must be taken with a very large grain of salt - and that's without getting into any discussions of how valid it is or isn't to use search results from google to do the measuring. - Jonathan M Davis
Re: Mixin templates are a pain at best, useless at worst for any non-trivial use case
On Tuesday, 5 June 2018 at 12:08:58 UTC, Simen Kjærås wrote: There's a reason for those rules in the language, namely function hijacking. This is an issue we take very seriously, and workarounds exists. So serious that there is no meaningful error message? These issues can be ameliorated as in your other post here, by wrapping the template mixin statement as well. This leads to a host of other problems - how do you specify arguments to the mixin template? How do you deal with aliased mixin templates? These issues may possibly be fixed, but it's gonna get ugly. I've posted on these newsgroups literally within the last three weeks about dealing with multiple different argument types (parsing template parameters) and aliases (__traits( identifier, Symbol ) does not match Symbol.stringof if it is an alias). As such, that's purely within the realms of "solvable by the programmer with new idioms" as I see it. This thing I'm posting about is solvable by giving up and generating a string to treat as code. ie the nuclear option when everything else in the language is unsuitable. This issue shows up every now and then, so we know it's a real issue, and the workarounds are clunky. At the same time, the current behavior is there for a reason, and is very unlikely to change. https://dlang.org/spec/template-mixin.html 1. A TemplateMixin takes an arbitrary set of declarations from the body of a TemplateDeclaration and inserts them into the current context. Everything you've talked about here directly conflicts with point number 1 of the mixin template spec. Point 3 of the spec makes a note of the implementation not actually doing the direct copy/paste that it mentions and instead embeds it in to a nested scope and imports it after the fact. Yet there appears to be quite a number of "except for this" clauses that aren't made clear. Clearly something has gone wrong somewhere along the way. So by that token: How many real world dollars have been wasted on function hijacking? Is this something a corporate client has been adamant about? Bringing up the #define macro analogy again, these are clearly similar problems that can happen in C/C++. So is it more of an ideological stand than a real-world one?
Re: pure functions cannot be removed, actually: pure vs. total
On Tuesday, 5 June 2018 at 17:47:15 UTC, Steven Schveighoffer wrote: Another observation: under the "infinite loops are important observable behavior" world-view, pure functions cannot be lazily evaluated either: pure int foo() { /*infinite loop */} void main(string[] args) { auto a = foo; writeln("hi"); if(args[1] == "printa") writeln(a); } With some optimizers, this can be rewritten: writeln("hi"); if(args[1] == "printa") writeln(foo); Which if foo is a *normally returning* function and not an infinite loop one, then this can save cycles in certain cases. But under your world-view, the optimization is invalid, because foo might have an infinite loop, and then the observable behavior changes (instead of printing nothing and infinite looping, "hi" is printed, and infinite loops). That's correct, this optimization is invalid. The only optimization that can arise from foo being pure is *subsequent* calls to foo being removed. -Steve On Tuesday, 5 June 2018 at 17:47:15 UTC, Steven Schveighoffer wrote: I'll repeat what I said in the PR where you made this similar comment, I don't think it is important to ensure a pure function that never returns is always called. Can you explain the benefit of such a thing? We've all heard of optimizers that reduce "code that does nothing" down to just a return statement, foiling people who are expecting benchmarks to run properly, why is this any different? Frankly speaking, we should not implement optimizations merely on the basis that we cannot immediately think of a case where they fail. For instance, a practical function that loops forever would be a find() call on an infinite range, such as a range returned by .repeat or .generate.
Re: pure functions cannot be removed, actually: pure vs. total
On 6/5/18 5:03 PM, FeepingCreature wrote: On Tuesday, 5 June 2018 at 17:47:15 UTC, Steven Schveighoffer wrote: Another observation: under the "infinite loops are important observable behavior" world-view, pure functions cannot be lazily evaluated either: pure int foo() { /*infinite loop */} void main(string[] args) { auto a = foo; writeln("hi"); if(args[1] == "printa") writeln(a); } With some optimizers, this can be rewritten: writeln("hi"); if(args[1] == "printa") writeln(foo); Which if foo is a *normally returning* function and not an infinite loop one, then this can save cycles in certain cases. But under your world-view, the optimization is invalid, because foo might have an infinite loop, and then the observable behavior changes (instead of printing nothing and infinite looping, "hi" is printed, and infinite loops). That's correct, this optimization is invalid. The only optimization that can arise from foo being pure is *subsequent* calls to foo being removed. I think Haskell would disagree with you: https://wiki.haskell.org/Lazy_evaluation On Tuesday, 5 June 2018 at 17:47:15 UTC, Steven Schveighoffer wrote: I'll repeat what I said in the PR where you made this similar comment, I don't think it is important to ensure a pure function that never returns is always called. Can you explain the benefit of such a thing? We've all heard of optimizers that reduce "code that does nothing" down to just a return statement, foiling people who are expecting benchmarks to run properly, why is this any different? Frankly speaking, we should not implement optimizations merely on the basis that we cannot immediately think of a case where they fail. For instance, a practical function that loops forever would be a find() call on an infinite range, such as a range returned by .repeat or .generate. But a call to find doesn't "do nothing". It takes a range and returns a range. We are specifically talking about strong-pure functions that return void, or even strong pure functions whose return value is ignored. And yes, we can actually prove that calls to pure functions do nothing based on the rules of pure functions, which is why the optimization is easy to prove correct. It's one of the reasons pure optimizations are much easier to reason about. However, if we have a wrinkle of "we have to make sure infinite loops execute their thing", then many pure optimizations get thrown out the window. -Steve
Re: stride in slices
On Tuesday, 5 June 2018 at 20:07:06 UTC, Ethan wrote: On Tuesday, 5 June 2018 at 19:05:27 UTC, DigitalDesigns wrote: For loops HAVE a direct cpu semantic! Do you doubt this? ... Right. If you're gonna keep running your mouth off. How about looking at some disassembly then. for(auto i=0; iUsing ldc -O4 -release for x86_64 processors, the initialiser translates to: mov byte ptr [rbp + rcx], 0 The comparison translates to: cmp r13, rcx ja .LBB0_2 And the increment and store translates to: mov byte ptr [rbp + rcx], 0 movsxd rcx, eax add eax, 3 So. It uses three of the most basic instructions you can think of: mov, cmp, j, add. Now, what might you ask are the instructions that a range compiles down to when everything is properly inlined? The initialisation, since it's a function, pulls from the stack. mov rax, qword ptr [rsp + 16] movsxd rcx, dword ptr [rsp + 32] But the comparison looks virtually identical. cmp rax, rcx jb .LBB2_4 But how does it do the add? With some register magic. movsxd rcx, edx lea edx, [rcx + r9] Now, what that looks like it's doing to me is combing the pointer load and index increment in to two those two instructions. One instruction less than the flat for loop. In conclusion. The semantics you talk about are literally some of the most basic instructions in computing; and that escaping the confines of a for loop for a foreach loop can let the compiler generate more efficient code than 50-year-old compsci concepts can. Ok asshat! You still don't get it! I didn't say ranges would not compile down to the same thing! Do you have trouble understanding the English language? You don't seem to get the concept where ranges are library solutions and someone can some along at any time and modify some code and WHAM! They no longer compile down to your efficient precious instructions. That is far more unlikely to occur with language semantics. Why is that so difficult for you to understand you sure do you have an attitude for someone that has difficulty with English.
Re: stride in slices
On 6/5/18 5:22 PM, DigitalDesigns wrote: On Tuesday, 5 June 2018 at 20:07:06 UTC, Ethan wrote: In conclusion. The semantics you talk about are literally some of the most basic instructions in computing; and that escaping the confines of a for loop for a foreach loop can let the compiler generate more efficient code than 50-year-old compsci concepts can. Ok asshat! You still don't get it! I didn't say ranges would not compile down to the same thing! Do you have trouble understanding the English language? Nope, he doesn't. Look at what you said: "Maybe in theory ranges could be more optimal than other semantics but theory never equals practice. " And now you have been shown (multiple times) that in practice ranges in fact outperform for loops. Including the assembly to prove it (which helps with this comment: "Having some "proof" that they are working well would ease my mind.") So tone down the attitude, you got what you *clearly* asked for but seem reluctant to acknowledge. Ranges are good, for loops are good too, but not as. So maybe you should just use ranges and use the correct optimization flags and call it a day? Or else use for loops and accept that even though they may not run as quickly, they are "safer" to use since some malicious coder could come along and add in sleeps inside the std.algorithm functions. -Steve
Re: D on top of Hacker News!
On Tuesday, 5 June 2018 at 20:15:07 UTC, Jonathan M Davis wrote: On Tuesday, June 05, 2018 15:09:56 Dejan Lekic via Digitalmars-d wrote: On Sunday, 3 June 2018 at 17:40:46 UTC, I love Ice Cream wrote: >> Is D really a top 20 language? I don't remember seeing it >> anywhere close to the top 20. >> >> https://www.tiobe.com/tiobe-index/ has them in 31 > > Top comment is kind of depressing. The right place to look is https://www.tiobe.com/tiobe-index/d/ I agree with other comments regarding TIOBE - they are constantly changing how they do statistics so they are not relevant source at all. Just look where Kotlin is there and that should pretty much tell you everything. I know at least 10 large companies that are moving from Java/Scala to Kotlin, yet Kotlin is at the bottom 50 table... Ridiculous... The TIOBE has never been a measurement of how much any given language is used. At best, it's been a measurement of which languages folks have been searching for. That can tell you something, but you have to understand what it's measuring to have any clue what it does tell you. And of course, because of how difficult it is to measure search results for a particular language, they keep changing their criteria. The result is that while the tiobe index may be interesting, it must be taken with a very large grain of salt - and that's without getting into any discussions of how valid it is or isn't to use search results from google to do the measuring. - Jonathan M Davis And all of the other metrics done by other groups that was provided that paints a similar picture? http://githut.info/ http://pypl.github.io/PYPL.html http://sogrady-media.redmonk.com/sogrady/files/2018/03/lang.rank_.118.png https://spectrum.ieee.org/computing/software/the-2017-top-programming-languages https://insights.stackoverflow.com/survey/2016 I'm not really intending to crap on anyone here. It's just the dismissal of a collection of data all pointing towards one particular conclusion is a bit strange. It seems like the interest in D is going down not up. I mean it could have a renaissance, but I'd imagine some work would have to be put into that to make it happen.
Re: stride in slices
On Tuesday, 5 June 2018 at 21:52:03 UTC, Ethan wrote: On Tuesday, 5 June 2018 at 21:22:27 UTC, DigitalDesigns wrote: Ok asshat! Take it to reddit. Back your arguments up with actual knowledge and intelligence, not unfounded agression. You are an idiot! You obviously do not understand basic logic. Unfounded aggression? Yep, way to see how you didn't start it! Must be nice being the bully!
Re: stride in slices
On Tuesday, 5 June 2018 at 21:22:27 UTC, DigitalDesigns wrote: Ok asshat! Take it to reddit. Back your arguments up with actual knowledge and intelligence, not unfounded agression.
Re: stride in slices
On Tuesday, 5 June 2018 at 21:54:20 UTC, DigitalDesigns wrote: You are an idiot! Take it to reddit. Back your arguments up with actual knowledge and intelligence, not unfounded agression.
Re: stride in slices
On Tuesday, 5 June 2018 at 19:18:15 UTC, Adam D. Ruppe wrote: On Tuesday, 5 June 2018 at 19:05:27 UTC, DigitalDesigns wrote: For loops HAVE a direct cpu semantic! Do you doubt this? What are they? And for bonus points, are they actually used by compilers? Then the final question: is the generated code any different than inlined ranges? It doesn't matter! The issue that I said was not that ranges were slower but that ranges exist on an abstract on top of language semantics! that means that they can never be faster than the language itself! Anything that a range does can never be faster than doing it by hand. This is not a hard concept to understand. I know everyone wants to defend their precious ranges but what happens is irrelevant in some particular case. Ranges could be 100x faster in some specific case but it doesn't change the fact that they are an abstraction on top of the language, not in the language. I've already pointed out, and made it clear, I will do it one last time: There is no guarantee(doesn't have to be 100% by the rule of god) by the compiler that a ranges performance will even come close to hand written code or that it won't all of a sudden change when someone decides to "optimize" it and actually makes it worse! These problems are far less likely to occur in a well established language semantic. I can't believe people are really defending library solutions as not having these issues, but I guess that is the nature of most humans.
Re: stride in slices
On Tuesday, 5 June 2018 at 22:20:08 UTC, DigitalDesigns wrote: It doesn't matter! The issue that I said was not that ranges were slower but that ranges exist on an abstract on top of language semantics! that means that they can never be faster than the language itself! Anything that a range does can never be faster than doing it by hand. This is the best part. Ranges *ARE* a language semantic. https://tour.dlang.org/tour/en/basics/ranges
Re: stride in slices
On Tuesday, 5 June 2018 at 21:35:03 UTC, Steven Schveighoffer wrote: On 6/5/18 5:22 PM, DigitalDesigns wrote: On Tuesday, 5 June 2018 at 20:07:06 UTC, Ethan wrote: In conclusion. The semantics you talk about are literally some of the most basic instructions in computing; and that escaping the confines of a for loop for a foreach loop can let the compiler generate more efficient code than 50-year-old compsci concepts can. Ok asshat! You still don't get it! I didn't say ranges would not compile down to the same thing! Do you have trouble understanding the English language? Nope, he doesn't. Look at what you said: "Maybe in theory ranges could be more optimal than other semantics but theory never equals practice. " And now you have been shown (multiple times) that in practice ranges in fact outperform for loops. Including the assembly to prove it (which helps with this comment: "Having some "proof" that they are working well would ease my mind.") No, you have shown a few fucking cases, why are you guys attacking me for being dense? You can't prove that ranges are more optimal than direct semantics! Do it! I'd like to see you try! So tone down the attitude, you got what you *clearly* asked for but seem reluctant to acknowledge. Ranges are good, for loops are good too, but not as. So maybe you should just use ranges and use the correct optimization flags and call it a day? Or else use for loops and accept that even though they may not run as quickly, they are "safer" to use since some malicious coder could come along and add in sleeps inside the std.algorithm functions. -Steve What it seems is that a few of you are upset because I didn't bow down to your precious range semantics and ask for clarification. At first I was jumped on then someone did some tests and found out that it wasn't so rosy like everyone thought. Of course, the work around is to force optimizations that fix the problem when the problem doesn't exist in for loops. Then you come along and tell me that specific cases prove the general case... that is real dense. You know, it takes two to have an attitude! I asked for information regarding stride. I got the range version, it turned out to be slower in some corner case for some bizarre reason. I was then told it required optimizations(why? That is fishy why the corner cause would be 200% slower for a weird edge case) and then I was told that ranges are always faster(which is what you just said because you act like one example proves everything). Every step of the way I am told "don't worry". You've already stepped in the shit once and you expect me to believe everything you say? Why is it so hard to have a test suite that checks the performance of range constructs instead of just getting me to believe you? Huh? Do you really think I'm suppose to believe every thing any asshat says on the net just because they want me to? Back up your beliefs, that simple. Provide timings for all the range functions in various combinations and give me a worse case scenario compared to their equivalent hand-coded versions. Once you do that then I will be able to make an informed decision rather than doing what you really want, which is except your world as authority regardless of the real truth.
Re: stride in slices
On Tuesday, 5 June 2018 at 22:28:44 UTC, DigitalDesigns wrote: On Tuesday, 5 June 2018 at 21:35:03 UTC, Steven Schveighoffer wrote: [...] [...] Does ranges not evaluate lazily on some cases. So it'll avoid unnecessary work...and be much faster and efficient. If I'm correct. [...]
Re: D on top of Hacker News!
On Tuesday, 5 June 2018 at 21:53:51 UTC, I love Ice Cream wrote: On Tuesday, 5 June 2018 at 20:15:07 UTC, Jonathan M Davis wrote: On Tuesday, June 05, 2018 15:09:56 Dejan Lekic via Digitalmars-d wrote: On Sunday, 3 June 2018 at 17:40:46 UTC, I love Ice Cream wrote: >> Is D really a top 20 language? I don't remember seeing it >> anywhere close to the top 20. >> >> https://www.tiobe.com/tiobe-index/ has them in 31 > > Top comment is kind of depressing. The right place to look is https://www.tiobe.com/tiobe-index/d/ I agree with other comments regarding TIOBE - they are constantly changing how they do statistics so they are not relevant source at all. Just look where Kotlin is there and that should pretty much tell you everything. I know at least 10 large companies that are moving from Java/Scala to Kotlin, yet Kotlin is at the bottom 50 table... Ridiculous... The TIOBE has never been a measurement of how much any given language is used. At best, it's been a measurement of which languages folks have been searching for. That can tell you something, but you have to understand what it's measuring to have any clue what it does tell you. And of course, because of how difficult it is to measure search results for a particular language, they keep changing their criteria. The result is that while the tiobe index may be interesting, it must be taken with a very large grain of salt - and that's without getting into any discussions of how valid it is or isn't to use search results from google to do the measuring. - Jonathan M Davis And all of the other metrics done by other groups that was provided that paints a similar picture? http://githut.info/ http://pypl.github.io/PYPL.html http://sogrady-media.redmonk.com/sogrady/files/2018/03/lang.rank_.118.png https://spectrum.ieee.org/computing/software/the-2017-top-programming-languages https://insights.stackoverflow.com/survey/2016 I'm not really intending to crap on anyone here. It's just the dismissal of a collection of data all pointing towards one particular conclusion is a bit strange. It seems like the interest in D is going down not up. I mean it could have a renaissance, but I'd imagine some work would have to be put into that to make it happen. The first link shows D having more repos. The third doesn't show changes in language popularity over time. I can't find any info about D usage over time in the other three links. The Stack Overflow survey isn't going to be informative anyway because most activity for D occurs here, not on SO, so it wouldn't be representative.
Re: stride in slices
On 05.06.2018 21:05, DigitalDesigns wrote: On Tuesday, 5 June 2018 at 18:46:41 UTC, Timon Gehr wrote: On 05.06.2018 18:50, DigitalDesigns wrote: With a for loop, it is pretty much a wrapper on internal cpu logic so it will be near as fast as possible. This is not even close to being true for modern CPUs. There are a lot of architectural and micro-architectural details that affect performance but are not visible or accessible in your for loop. If you care about performance, you will need to test anyway, as even rather sophisticated models of CPU performance don't get everything right. Those optimizations are not part of the instruction set so are irrelevant. They will occur with ranges too. ... I was responding to claims that for loops are basically a wrapper on internal CPU logic and nearly as fast as possible. Both of those claims were wrong. For loops HAVE a direct cpu semantic! Do you doubt this? ... You'd have to define what that means. (E.g., Google currently shows no hits for "direct CPU semantics".) Cpu's do not have range semantics. Ranges are layers on top of compiler semantics... you act like they are equivalent, they are not! I don't understand why you bring this up nor what you think it means. The compiler takes a program and produces some machine code that has the right behavior. Performance is usually not formally specified. In terms of resulting behavior, code with explicit for loops and range-based code may have identical semantics. Which one executes faster depends on internal details of the compiler and the target architecture, and it may change over time, e.g. between compiler releases. All range semantics must go through the library code then to the compiler then to cpu. For loops of all major systems languages go almost directly to cpu instructions. for(int i = 0; i < N; i++) translates in to either increment and loop or jump instructions. ... Sure, or whatever else the compiler decides to do. It might even be translated into a memcpy call. Even if you want to restrict yourself to use only for loops, my point stands. Write maintainable code by default and let the compiler do what it does. Then optimize further in those cases where the resulting code is actually too slow. Test for performance regressions. There is absolutely no reason why any decent compiler would not use what the cpu has to offer. For loops are language semantics, Ranges are library semantics. Not really. Also, irrelevant. To pretend they are equivalent is wrong and no amount of justifying will make them the same. Again, I don't think this point is part of this discussion. I actually do not know even any commercial viable cpu exists without loop semantics. What does it mean for a CPU to have "loop semantics"? CPUs typically have an instruction pointer register and possibly some built-in instructions to manipulate said instruction pointer. x86 has some built-in loop instructions, but I think they are just there for legacy support and not actually something you want to use in performant code. I also no of no commercially viable compiler that does not wrap those instructions in a for loop(or while, or whatever) like syntax that almost maps directly to the cpu instructions. ... The compiler takes your for loop and generates some machine code. I don't think there is a "commercially viable" compiler that does not sometimes do things that are not direct. And even then, there is no very simple mapping from CPU instructions to observed performance, so the entire point is a bit moot. Also, it is often not necessary to be "as fast as possible". It is usually more helpful to figure out where the bottleneck is for your code and concentrate optimization effort there, which you can do more effectively if you can save time and effort for the remaining parts of your program by writing simple and obviously correct range-based code, which often will be fast as well. It's also often not necessary to be "as slow as possible". This seems to be quoting an imaginary person. My point is that to get even faster code, you need to spend effort and often get lower maintainability. This is not always a good trade-off, in particular if the optimization does not improve performance a lot and/or the code in question is not executed very often. I'm not asking for about generalities but specifics. It's great to make generalizations about how things should be but I would like to know how they are. That's a bit unspecific. Maybe in theory ranges could be more optimal than other semantics but theory never equals practice. I don't know who this is addressed to. My point was entirely practical.
Phobos, minimal runtime, -betterC compatibility documentation
I'm more interested in no/minimal runtime[1] than -betterC for my use cases. I think it will be good to have the document mention if the function is supported without the druntime and/or with -betterC. This documentation can be the module level or function level. Is this possible and/or is it worth it? I understand that using druntime function with -betterC will make the compiler throw error. But it will be good to know it up front via doc if a function uses druntime or not. [1] https://dlang.org/changelog/2.079.0.html#minimal_runtime
Re: Phobos, minimal runtime, -betterC compatibility documentation
On Wednesday, 6 June 2018 at 01:34:13 UTC, Arun Chandrasekaran wrote: I'm more interested in no/minimal runtime[1] than -betterC for my use cases. I think it will be good to have the document mention if the function is supported without the druntime and/or with -betterC. This documentation can be the module level or function level. Is this possible and/or is it worth it? I understand that using druntime function with -betterC will make the compiler throw error. But it will be good to know it up front via doc if a function uses druntime or not. [1] https://dlang.org/changelog/2.079.0.html#minimal_runtime What we actually need is to have the runtime itself to be well-documented. In doing so, one would be able to see which features are implemented in the runtime and which features aren't, so what is and isn't supported in a "minimal runtime" would be self-evident. In lew of that, however, I'll refer you to documentation "object", "core", and "rt" here: https://dlang.org/phobos/index.html. Another good resource is https://wiki.dlang.org/Runtime_Hooks; it's outdated, but still relevant. Please also understand that one of the primary use cases for the "minimal runtime" changes in 2.079 is to allow users to port the runtime to a new platform incrementally in a pay-as-you-go fashion. For that, you'll need to learn the details of the runtime anyway. Prior to the changes in 2.079, you had to implement a large part of the runtime just to get a build, and most of that code would have never even been called from your program. It was ridiculous and a major barrier to entry. With 2.079, you can now implement just what you need incrementally, and that will make it much easier to learn the runtime. What I'm trying to say, is the "minimal runtime" approach to using D is for those who wish to become runtime hackers, and are willing to study and experiment in order to learn how to take control of the runtime for themselves. The reason the phrase "minimal runtime" is often used over "no runtime" is because it is up to you to decide which features of D to implement or not implement. That being said, understand that -betterC does not link in the runtime, so anything not supported by -betterC will also not be supported by a bare runtime. Therefore the documenation at https://dlang.org/spec/betterc.html is still relevant to the "minimal runtime" approach.There are differences. For example, I think -betterC forwards asserts to the C library, while a bare runtime would not. But, the differences are few. You're also welcome to ask questions. I'm the one primarily responsible for those "minimal runtime" changes, and I'd be happy to help you if I can. Mike P.S. You're probably not going to have much success using Phobos in a "minimal runtime" scenario. I'm exploring a way to get around that at https://github.com/JinShil/utiliD.
Help with semaphoreci issue?
I have 2 DMD PR's that show this issue with semaphoreci: https://semaphoreci.com/dlang/dmd-2/branches/pull-request-8336/builds/1 I don't understand what's wrong, and whether or not it's my fault... If it's not, I guess someone needs to know about it?