http://inversethought.com/hg/medcouple/file/tip/medcouple.py...
http://inversethought.com/hg/medcouple/file/tip/medcouple.d#...
http://inversethought.com/hg/medcouple/file/tip/medcouple.py...
http://inversethought.com/hg/medcouple/file/tip/medcouple.d#...
Most of the standard library function calls return some opaque Result type which isn't obvious how to progress from. Only after some googling you'll learn that if you import std.array you can use .array() on the Result and get something usable. Oh, and I don't even know if it's possible to pass such Result to a function because you have to use auto to declare it.
Oh, and you can also use type deductions for function declarations! Just make it a template and let D figure out for you what type you want, or use typeof to record the type you want and use that typename in your function declaration.
The python version of it would be calling `list()` on things all the time, which you might not always want to do.
Perhaps it's just my own incompetence though!
Input/Output Range > Forward Range > Bidirectional Range > Random Access Range
Input ranges provide the following API:
bool empty()
T front()
void popFront()
Forward ranges provide the same API, and also add a "save" function that creates a copy of the range's current state.Bidirectional ranges add "back" and "popBack" functions, which don't really need any explanation.
Random access ranges additionally add a "length" function and constant-time array-like indexing.
In addition to most functions in std.algorithm _returning_ ranges, most of them also _accept_ ranges. Therefore, you can freely pass the result of any function in std.algorithm into another function that takes a range, and it should all just work. It's pretty much the same deal as in Rust/Java/Swift/etc. with their various iterator protocols, although the API for ranges in D is more influenced by C++.
For example, the first Project Euler problem, using a range-based approach:
import std.algorithm;
import std.range;
import std.stdio;
void main()
{
//List all the natural numbers below 1000 that are multiples of 3 or 5
auto natsBelow1000 = iota(1000); //iota returns a range that lazily computes the numbers from 0-999
auto multiplesOf3Or5 = natsBelow1000.filter!(n => n % 3 == 0 || n % 5 == 0); //filter accepts a range as an argument, which it lazily filters according to the given predicate
auto sum = multiplesOf3Or5.sum(); //Sum accepts a range of "summable" items and computes the... sum
writeln(sum); //Prints 233168
}
A D programmer wouldn't generally write things this way, preferring to make a more idiomatic "range chain" like you'd see with Java's streams or Rust's iterators, but you get the idea.As you might have guessed, arrays are also ranges - random access ranges - which is why they're so easy to use.
I would highly recommend against putting `.array` everywhere in your code, as it will force the range you pass to it to be eagerly evaluated and allocate more memory from the GC. It's much better to take some initial data store, like an array, do all your filtering and mapping, etc. on it, and when you're done, _then_ turn it back into an array with a call to `.array`. That way you'll get all the lazy iteration and low memory footprint of ranges, and then at the end you have a nicely allocated array of data with the result that is easy to work with.
Honestly, though, in most of my code I usually just pass around ranges as they're very good for creating interlocking adapters over different backing stores. One really great article on advanced usage of ranges is H. S. Teoh's article on Component Programming with Ranges: https://wiki.dlang.org/Component_programming_with_ranges
A couple great resources on ranges in D:
http://www.informit.com/articles/printerfriendly/1407357
https://tour.dlang.org/tour/en/basics/ranges
How do I pass this output to some other function without doing .array()? It's rare that you do all your processing in one method. Should I do this:
void processFurther(T)(T t) if isInputRange!T { } ?
I mean, it would probably work, but I don't like how the conditions are detached from type definitions :S
> I don't like how the conditions are detached from type definitions
I can understand that; it's something that takes a bit of getting used to. See https://dlang.org/concepts.html for an explanation of template constraints and why they were designed this way.
This is by design, e.g. map could not be lazy if it returned an array.
> Oh, and I don't even know if it's possible to pass such Result to a function because you have to use auto to declare it.
templates, void use(T)(T x) [auto ref if you feel fancy]
Whether D "clicks" for someone might be more a matter of subjective taste than what languages they're used to.
As for D templates, they puzzled me until I read Andrei's D Programming book, which made everything clear. They're less narrow than C++ templates, more like directives for a syntax/scope-aware C preprocessor.
You can use them for more than just polymorphic functions; they're a way to pass source code around the program at compile-time, for almost any purpose whatsoever.