Re: Pair literal for D language
On Saturday, 28 June 2014 at 21:12:06 UTC, Timon Gehr wrote: On 06/28/2014 06:11 PM, Mason McGill wrote: On Saturday, 28 June 2014 at 09:15:29 UTC, Dicebot wrote: On Friday, 27 June 2014 at 22:01:21 UTC, Mason McGill wrote: I like DIP54 and I think the work on fixing tuples is awesome, but I have 1 nit-picky question: why is it called TemplateArgumentList when it's not always used as template arguments? void func(string, string) { } TypeTuple!(string, string) var; var[0] = I'm nobody's ; var[1] = template argument!; f(var); Why not a name that emphasizes the entity's semantics, like StaticList/ExpandingList/StaticTuple/ExpandingTuple? Because it is defined by template argument list and has exactly the same semantics as one. And semantics are unique and obscure enough that no other name can express it precisely. Understood. I was just expressing my initial impression: that it seemed strange that a symbol declared as a `TemplateArgumentList` was neither passed nor received as template arguments. That would be strange, but it isn't. TypeTuple!(string, string) var; ^ passed here alias TypeTuple(T...)=T; - aliased here ^~~~ received here Hence: TypeTuple!(string, string) var; ^~ this is actually the template argument list that was passed In any case, I just call it 'Seq'. I understand, but I was talking about `var` being referred to as a `TemplateArgumentList` when it's not used as such. It's used as an `ArgumentList`, just not a `TemplateArgumentList`. Cheers, Mason
Re: Pair literal for D language
On Saturday, 28 June 2014 at 09:15:29 UTC, Dicebot wrote: On Friday, 27 June 2014 at 22:01:21 UTC, Mason McGill wrote: I like DIP54 and I think the work on fixing tuples is awesome, but I have 1 nit-picky question: why is it called TemplateArgumentList when it's not always used as template arguments? void func(string, string) { } TypeTuple!(string, string) var; var[0] = I'm nobody's ; var[1] = template argument!; f(var); Why not a name that emphasizes the entity's semantics, like StaticList/ExpandingList/StaticTuple/ExpandingTuple? Because it is defined by template argument list and has exactly the same semantics as one. And semantics are unique and obscure enough that no other name can express it precisely. Understood. I was just expressing my initial impression: that it seemed strange that a symbol declared as a `TemplateArgumentList` was neither passed nor received as template arguments.
Re: Pair literal for D language
I like DIP54 and I think the work on fixing tuples is awesome, but I have 1 nit-picky question: why is it called TemplateArgumentList when it's not always used as template arguments? void func(string, string) { } TypeTuple!(string, string) var; var[0] = I'm nobody's ; var[1] = template argument!; f(var); Why not a name that emphasizes the entity's semantics, like StaticList/ExpandingList/StaticTuple/ExpandingTuple?
Re: Designing a matrix library for D
On Tuesday, 24 June 2014 at 04:36:04 UTC, ed wrote: On Monday, 23 June 2014 at 21:08:03 UTC, Mason McGill wrote: [snip] Concepts: InputGrid: anything with a size (size_t[n]) and n-dimensional opIndex. OutputGrid: anything with a size (size_t[n]) and n-dimensional opIndexAssign. [snip] Cheers, Mason I don't think 'Grid' is not a good name for the type. The term Grid is generally used to refer to any sort of grid; regular, semiregular, irregular, unstructured, curvilinear etc. etc. grids. When you're talking about sampling on a grid, warping can either be thought of as warping the grid, or warping the function to be sampled. My library happens to work in terms of the second approach, so it is (pedantically) consistent. I see your point, though. They are all very different in their use and internal representations. Often a grid will have support for metadata at each point (GIS etc.) whereas a matrix will not. I think the word Matrix is a better fit, because that is what they these types are. Not quite. Matrix connotes 2-dimensional tensors (in the linear algebra sense). The library I'm developing at work is for manipulating multidimensional arrays, which don't have the same semantics people expect from matrices (representing linear operators). However, the name Array already refers to at least 3 data structures in D, so it was out. I picked Grid because the library is for processing data sampled regularly on n-dimensional grids (mostly vision). With my library, you could represent complex data in a GIS via a grid of structures, or multiple grids (layers). If you're not convinced, I intend to release my work under a liberal license, so feel free to download it and find/replace Grid - Matrix :) Also, check out this other option if you haven't already: http://denis-sh.bitbucket.org/unstandard/unstd.multidimarray.html
Re: Designing a matrix library for D
On Monday, 23 June 2014 at 16:45:28 UTC, bearophile wrote: I'm glad to hear there's interest in this! I've actually been working on a generic multidimensional array library myself (on and off) for the past few months (I'm hoping to have a well-documented dub package by the end of the summer). It's a bit of a hybrid between Julia's `AbstractArray`, NumPy's `ndarray`, Numba, and std.range, and I think it has a very D feel. It is, however, designed for processing sampled signals (rather than matrix algebra), which may be more or less in line with different people's interests. Concepts: InputGrid: anything with a size (size_t[n]) and n-dimensional opIndex. OutputGrid: anything with a size (size_t[n]) and n-dimensional opIndexAssign. Functionality: - Lazy `map` and `reduce`. - Lazy `zip` with built-in broadcasting. - Lazy n-dimensional convolution and cross-correlation. - Lazy sampling and interpolation. - `collect` to force evaluation. - Element-wise operators and and fancy indexing via mixins*. - Everyone's favorite MATLAB-style constructors (`zeros`, `identity`, `meshGrid`, etc.) - Audio/Video and JSON I/O, via GStreamer (though this probably ought to be a separate package). *Because D doesn't allow UFCS for operators, which is silly, but that's the way it is. Other features: - Compatibility with an automatic binding generator I've been working on. - Testing, because I've been using this at work :) If people want to use this, it might make sense to add linear algebra to this package rather than building a separate, incompatible algebra library (see this thread: http://comments.gmane.org/gmane.comp.lang.julia.devel/14533). I did a lot of thinking about the level of abstraction that would be the most useful, and I settled on something like Julia's `AbstractArray` because it fits into D nicely (like ranges, but different!) and easily maps onto something that can be passed to other languages (a block of memory with size/strides metadata). As in Julia, I decided to make rank (`nDim!grid`) a compile-time entity since 1) Writing rank-branching code for NumPy is cumbersome and error prone; rank should be part of overload resolution. 2) It speeds up component-programming-style operations without requiring leaky abstractions (having to specialize on concrete grid types). It's a busy week so I probably won't be able to follow this thread, but I wanted to let you know I was working on this to avoid duplicated efforts, etc. Cheers, Mason
Re: Time to rename D to @D !?
On Monday, 23 June 2014 at 20:34:59 UTC, Jonathan M Davis via Digitalmars-d wrote: It would be very cool if we could remove @ from all of the built-in attributes, but the whole reason that they have them in the first place is because it was decided that we didn't want to add new keywords - and that was several years ago when D had a smaller user base. So, I really don't see it changing at this point. If anything, we might go the _other_ way and add @ onto the attributes that don't have it in order to make them more consistent (though I hope that we don't do that, because it's ugly and more verbose). People (I've talked to) seem to like Python decorators and Java annotations, and they have mandatory @ characters. I like the @ because it helps me (and my editor) distinguish between words that *define* a computation (return type, parameters, etc.) and words that *describe* a computation (attributes).
Re: Designing a matrix library for D
On Monday, 23 June 2014 at 21:33:40 UTC, H. S. Teoh via Digitalmars-d wrote: You are far from the first one to write a multidimensional array library in D. Denis has already done this some time ago, and I have, too. I've seen Denis' library. It seems nice, but it's a lot more concrete that what the original post was discussing. Is yours online somewhere (for inspiration)? I've thought about this a lot, and my conclusion is that matrix algebra is best left to a matrix-specific library wrapper that endows matrix algebra properties on top of a generic multidimensional array type. The main reason is that matrix algebra is rather peculiar to matrices specifically, particularly the non-commutative matrix product, and does not have very many useful usages outside of matrix algebra itself; yet multidimensional arrays in general are useful in a wider scope. So in my mind, there are several components that are needed here: - A generic multidimensional array, as a data container. This can be a set of diverse concrete types, e.g. to represent sparse matrices, etc.. No domain-specific operations are specified for these containers; they are purely for storage and access only. - Specialized array types, like matrices which add matrix algebra semantics to the underlying multidimensional array storage container (e.g., matrix product), or tensor wrappers (endows tensor product semantics on the underlying container). - Algorithms: these take any multidimensional array, or specialized matrix type (depending on the purpose of each algorithm), and operate on them using a common multidimensional array API. They should be as generic as they can be, but no more, e.g., LU decomposition algorithms would take a matrix type rather than the general multidimensional array type, because it is specific to matrices, whereas per-element summation would take any general multidimensional array type, since it doesn't need matrix-specific properties. Similarly, subarray operations should be able to work with any multidimensional array type, since it simply provides a restricted view on the underlying storage container, but doesn't depend on the implementational specifics of the container itself. Seems reasonable. I think the best solution would be a generic multidimensional concept (analogous to the input range concept) that will fit all of our multidimensional array implementations. Algorithms that can work with diverse ranks shouldn't care if the rank of a particular concrete type is compile-time or runtime, for example. Let the algorithms be adaptable (up to practicality, of course -- if an algo can't work or works very poorly with dynamic rank, then just add a constraint that requires static rank, for example), and the user can choose which concrete type(s) best suits his needs. One possible issue with dynamically-ranked grids is concept-testing. `isInputGrid!Collection` needs to check if `Collection` has a `size` property, and can be indexed with `size.length` indices. If this is to be done at compile-time, `size.length` needs to be constant. The concrete types can then be provided by a separate module, and if we do it right, should be interoperable with each other. Definitely an important design goal. You seem quite knowledgeable on this topic and I hope we can continue this conversation when my work on this is further along.
Re: Why does this work?
On Monday, 23 June 2014 at 08:30:44 UTC, h_zet wrote: import std.typecons; auto foo2(R)(R foopara){ return tuple(foopara, is(R==int)); } void main(){ auto tuple(a,b) = foo2(1); } I'm expecting some error such as can not act as left value but when I compiled this, no error occured. DMD version is DMD64 v2.065.(ldc2 exited with error function declaration without return type) Why does this work? Or it is a bug? Strange behavior, indeed. It took me a minute, but I think I know what's going on, and I'm pretty sure it's a bug. D recently introduced a short syntax for function-like templates: enum a(b) = some_value; It looks like this also (sort of) works with other qualifiers, which I believe it shouldn't. Here's a minimal example that might be good to put in a bug report: void main() { enum a(x) = some_value; // Good. auto b(x) = some_value; // Huh? // This also works for `const`, `static`, etc. }
Re: Why does this work?
On Monday, 23 June 2014 at 09:29:15 UTC, Mason McGill wrote: Strange behavior, indeed. It took me a minute, but I think I know what's going on, and I'm pretty sure it's a bug. D recently introduced a short syntax for function-like templates: enum a(b) = some_value; It looks like this also (sort of) works with other qualifiers, which I believe it shouldn't. Here's a minimal example that might be good to put in a bug report: void main() { enum a(x) = some_value; // Good. auto b(x) = some_value; // Huh? // This also works for `const`, `static`, etc. } It looks like I'm mistaken. Variable templates are supposed to exist. Please ignore the previous post.
Re: nothrow function callbacks in extern(C) code - solution
On Thursday, 19 June 2014 at 23:41:25 UTC, H. S. Teoh via Digitalmars-d wrote: Pretty soon, we need an attribute algebra to express these complicated relationships. It would be nice to have a solution that can handle all of these cases without exploding complexity in the syntax. Here's one idea: Attributes can be thought of as declarative compile-time parameters--they don't directly define a computation, but they feel like compile-time parameters in that - They are variable in number. - They may take on many possible values. - They may be parameterized (like `extern`). - They play a role in overload resolution. - Their combinations may lead to combinatorial explosions that can hopefully be mitigated with metaprogramming. My point is, many of the problems we're encountering with attributes have already been solved (via templates, tuples, CTFE, `static if`, etc.) Attribute propagation would be simple (not trivial, but appropriately simple) for user-defined attributes, because they can be arbitrary expressions. If built-in attributes were just treated as pre-defined symbols, they could be manipulated with templates and CTFE: enum mayThrow(alias func) = staticIndexOf!(nothrow, functionAttributes!func) == -1; template throwsLike(alias func) { static if (mayThrow!func) enum throwsLike = tuple().expand; else enum throwsLike = nothrow; } void call(alias func)() @throwsLike!func { func(); } (This thread may be relevant: http://forum.dlang.org/thread/hfmulninvghjntqkp...@forum.dlang.org)
Re: DIP64: Attribute Cleanup
On Friday, 20 June 2014 at 22:01:31 UTC, Timon Gehr wrote: On 06/20/2014 09:22 PM, Brian Schott wrote: http://wiki.dlang.org/DIP64 Attributes in D have two problems: 1. There are too many of them and declarations are getting too verbose 2. New attributes use @ and the old ones do not. I've created a DIP to address these issues. Why not make the built-in attributes proper symbols instead and use alias Seq(T...)=T; alias spiffy = Seq!(pure,nothrow,safe); float mul(float a, float b) @spiffy{ } ? This will also allow use cases such as passing attributes by alias. I think this would make the language a lot cleaner, and can be taken even further: @extern(C++, some.namespace) class C { @private int x; } Here `extern` is a regular function that returns an instance of some compiler-defined type. This makes built-in attributes just particular cases of properties (that happen to be recognized by the compiler). Attribute and property are pretty much synonyms in English, and it always seemed strange to me that D had to define them as different--yet confusingly similar--entities.
Re: DIP64: Attribute Cleanup
On Sunday, 22 June 2014 at 05:18:05 UTC, Jonathan M Davis via Digitalmars-d wrote: On Sun, 22 Jun 2014 00:12:20 + Mason McGill via Digitalmars-d digitalmars-d@puremagic.com wrote: Attribute and property are pretty much synonyms in English, and it always seemed strange to me that D had to define them as different--yet confusingly similar--entities. They're not even vaguely similar in D. A property is a member of a struct or class which is a variable or a function which emulates a variable, whereas attributes are annotations put on symbols (currently just classes, structs, and functions AFAIK) which indicate extra information to the compiler and to type introspection. So, while I can see why you might dislike the fact that attribute and property do not mean the same thing in D, they're _not_ at all similar it how they're used, so I find it very odd if anyone is confusing them. And it's not like D pioneered these meanings for attributes and properties. C# uses them for the same things. - Jonatahn M Davis I was referring to the `Property` and `PropertyIdentifier` entities in the D grammar (http://dlang.org/attribute.html), which are special cases of attributes. New-style attributes, like property, safe, and nogc, are `PropertyIdentifier`s and need to be written with the @ character. Older, non-property attributes, like pure and nothrow, do not. Sorry if this wasn't clear in the former post.
Re: async/await in F#
Good tutorial choices; they're very well-written. I haven't used F# much, but here's my take (call me out on any mistakes in my understanding): `async` being just a particular instance of a class of user/library-defined computation expression has a lot of good things going for it. This setup provides an alternative to nested lambda expressions that's more readable in some cases. And it's far more future-proof than C#'s approach. There was one thing I didn't like about monadic F#: it's hard to read without being intimately familiar with the workflow you are using (e.g. `async`). If I see a `for..do` expression inside an `async` block, I don't know whether `async` has overridden that syntax unless I open up the `async`'s documentation. It seems this is easily side-stepped by using explicit syntax (e.g. `for!` instead of `for`), which makes me wonder why the F# designers made some of the syntax overrides stand out (`let!` and `do!`), but not others (`return` and `while..do`). Finally, I wonder what happens if you nest computation expressions: async { query { /* Code for an asynchronous query. */ } } My guess it that the inner workflow (`query`) transforms the code inside it, then passes the result to the outer workflow, which then transforms it further. This could get confusing quickly, but I suppose you'd only write something like this if it was the best way to express your intent, which means the alternatives were *more* confusing.
Re: foreach
On Thursday, 12 June 2014 at 15:00:20 UTC, Manu via Digitalmars-d wrote: I often find myself wanting to write this: foreach(; 0..n) {} In the case that I just want to do something n times and I don't actually care about the loop counter, but this doesn't compile. You can do this: for(;;) {} If 'for' lets you omit any of the loop terms, surely it makes sense that foreach would allow you to omit the first term as well? I see no need to declare a superfluous loop counter when it is unused. Seems like a nice idea. Especially useful when it comes to reading other people's code: foreach (i; 0..n) { some(); long(); list(); of(); tasks(); } // I always double back--wait, where did they use `i`?
Re: Optionally strongly typed array indexes
On Friday, 6 June 2014 at 20:22:35 UTC, Philippe Sigaud via Digitalmars-d wrote: Sorry to intrude, but you can also get: enum newton = 1.kg/m/s^^2; Good point. I actually learned D had an exponentiation operator just yesterday. It definitely helps readability in this case.
Re: Optionally strongly typed array indexes
On Thursday, 5 June 2014 at 09:23:00 UTC, bearophile wrote: Sorry for my answers coming so slowly. Hah! I'm on these forums (selfishly) trying to understand/improve D for my own use at work, while you seem to be helping/teaching/contributing for the sake of it. I'm continually surprised by how pleasant and professional this community is; nothing at all to be sorry for! void main() { import std.stdio; foreach (i; 0 .. 10) { writeln(i); i++; } } Currently this prints just the even numbers, I think this is a little weird. That is weird. It goes counter to the idea of `i` coming from the range. Though, I'd say someone writing that code is asking for strange behavior, so it's not much of an issue. Generally in my D code I write like this, as explained here: http://blog.knatten.org/2011/11/11/disempower-every-variable/ I agree, with the caveat of trying to not add so much noise that it becomes unreadable. Immutable by default is probably the right choice for a modern language. Yes, or at least making operations with side effects look different from operations without. I think this is one part of the larger problem of representing units. Units of measure introduce a good amount of complexity and logic that is absent in the idea of giving strongly types to array indexes. You don't need to convert inches to centimetres, True. You don't need to perform a compile-time dimensional analysis for the correctness of expressions. I'd argue you do, at least given my understanding of the goals of strongly-typed array indices. For example, consider strided indexing: const dogs = [Rover, Fido, Rex].of!dog; const cats = [Fluffy, Mr. Whiskers].of!cat; // This should work. const i1 = index!dog(1); dogs[i1]; // This should not work. const i2 = index!cat(1); dogs[i2]; // This should work. const i3 = 2 * i1; dogs[i3]; // This should not work. const i4 = i2 * i1; dogs[i4]; So, the library needs to do some form of dimensional analysis to allow typed indices to be multiplied by unit-less scalars, but not scalars with units. You don't need to keep in mind the 0-based problems of converting Celsius to Fahrenheit. True. This is why I said the problem of strongly typed array indexes is *part* of the problem of units, not equivalent to it. You don't need to solve the syntax problems of attaching m / s somehow to number literals. Also true, though as a side note, I think a library solution for this could be quite nice: enum newton = 1.as!kg*m/s^2; // One possibility. enum newton = 1*kg*m/square(s); // Another. though I'll have to think about whether it covers all the cases you're interested in. Another problem is visible in this code, I have a function bar() that must receive a different value for each item of the enum Foo. If I use an associative array, the compiler doesn't catch at compile-time the bug of the missing Foo.B case: enum Foo : ubyte { A, B } void bar(int[Foo] aa) {} void main() { bar([Foo.A: 10]); } And often using an associative array for this purpose is a waste of memory and computation. The Ada compiler is able to catch this bug at compile-time, using a simple fixed-size array (exactly as long as the number of items in the enum) with indexes strongly typed as Foo. So the array literal must contain all possible indexes only once: import std.traits: EnumMembers; enum Foo : ubyte { A, B } void bar(int[@typed(Foo) EnumMembers!Foo.length] input) {} void main() { bar([Foo.A: 10, Foo.B: 20]); } If you give a strong type to the array index you avoid that bug at compile time. (To be accepted as index type, an enumeration must behave nicely, all such tests can be done at compile-time). That's quite clever, though couldn't it also be done with a library? enum Foo : ubyte { A, B } enum nFoo = EnumMembers!Foo.length; alias AllFoo = WithUnits!(int[nFoo], Foo); void bar(AllFoo) {} void main() { bar(AllFoo([/*A*/ 10, /*B*/ 20])); }
Re: Optionally strongly typed array indexes
On Wednesday, 4 June 2014 at 09:43:20 UTC, bearophile wrote You can give strong typing to indexes of a matrix library, this doesn't need language changes. So a dynamic array library in Phobos could fulfil most of the possible desires or needs for strongly typed indexes. But you lose some of the convenience of the built-in arrays, and you have to import a bulky library that you are mostly not using. I see several places in all kinds of D code where strongly typed indexes can help tell things apart more clearly and safely, but I think only in some of such situations programmers are willing to import a numpy-like library just to have strong typing. I'll have to check out Ada to get a sense of how this feature works and how people use it. In D learn I see that people don't even add immutable to the foreach variable that spans an interval. I noticed you did that, though I haven't seen this much on Dlang.org. Is this considered idiomatic? Coming mostly from JavaScript/Python/CUDA C++ I'm not sure how I feel about the terseness/safety trade-off (I can honestly see it both ways). So I don't expect people to import numpy just to give types to two indexes of two 1D arrays. And statistically I think such cases of just two or tree 1D arrays are much more common than numerical code that manages several matrices with a good matrix library. Good point. Though, I don't think adding compiler support for strongly typed array dimensions is the full solution. I think this is one part of the larger problem of representing units. Other languages have solutions to this (I particularly like F#'s: http://en.wikibooks.org/wiki/F_Sharp_Programming/Units_of_Measure), and it would be very nice to see something this in Phobos: /* User code. */ import std.awesome_unit_library: Unit, of; // Unit: defines new types that can be multiplied divided. // of: wraps a container in a stricter version, enforcing units. alias Name = Unit!name; alias Food = Unit!food; auto names = [Fred, Alice, Sue].of!Name; auto foods = [Apple, Orange, Tofu].of!Food; foreach (name; [Bill, Ted].of!Name) { names ~= name; // This compiles happily. foods ~= name; // This does not compile, preventing // Bill and Ted from being eaten. }
Re: Optionally strongly typed array indexes
On Wednesday, 4 June 2014 at 18:46:04 UTC, Mason McGill wrote: /* User code. */ import std.awesome_unit_library: Unit, of; // Unit: defines new types that can be multiplied divided. // of: wraps a container in a stricter version, enforcing units. alias Name = Unit!name; alias Food = Unit!food; auto names = [Fred, Alice, Sue].of!Name; auto foods = [Apple, Orange, Tofu].of!Food; foreach (name; [Bill, Ted].of!Name) { names ~= name; // This compiles happily. foods ~= name; // This does not compile, preventing // Bill and Ted from being eaten. } You could actually just let the `of` template create the `Unit` type for you, if you want to be terse: import std.awesome_unit_library: of; auto names = [Fred, Alice, Sue].of!name; auto foods = [Apple, Orange, Tofu].of!food; foreach (name; [Bill, Ted].of!name) { names ~= name; // This compiles happily. foods ~= name; // This does not compile, preventing // Bill and Ted from being eaten. } It looks like this library solution puts user work at or below the level of your proposed syntax, though I'll have to think about whether it covers all the cases you're interested in.
Operator/concept interoperability
I have a numerical/multimedia library that defines the concept of an n-dimensional function sampled on a grid, and operations on such grids. `InputGrid`s (analogous to `InputRange`s) can be dense or sparse multidimensional arrays, as well the results of lazy operations on other grids and/or functions (map/reduce/zip/broadcast/repeat/sample/etc.). UFCS has been extremely beneficial to my API, enabling things like this: DenseGrid!(float, 2) x = zeros(5, 5); auto y = x.map!exp.reduce!max; without actually defining `map` inside `DenseGrid` or `reduce` inside `MapResult`. `map` and `reduce` are defined once, at module scope, and work with any `InputGrid`. As this is numerical code, it would be great to be able to do this with operators, as is possible in C++, Julia, and F#: auto opUnary(string op, Grid)(Grid g) if (isInputGrid!Grid) { /* Enable unary operations for *any* `InputGrid`. */ } DenseGrid!(float, 2) x = zeros(5, 5); auto y = -x; This is currently not supported, which means users of my library get functions like `map` and `reduce` that work out of the box for any grids they define, but they need to do extra work to use convenient operator syntax for NumPy-style elementwise operations. Based on my limited knowledge of DMD internals, I take it this behavior is the result of an intentional design decision rather than a forced technical one. Can anyone explain the reasoning behind it? Also, does anyone else have an opinion for/against allowing the definition of operators that operate on concepts? Thanks for your time, -MM
Re: Operator/concept interoperability
On Tuesday, 3 June 2014 at 22:05:29 UTC, TheFlyingFiddle wrote: Well one reason for this is that unlike methods it is hard to resolve ambiguity between diffrent operator overloads that have been defined in diffrent modules. Example: 2D-vectors //vector.d struct Vector { float x, y; } //cartesian.d Vector opBinary(string op : +)(ref Vector lhs, ref Vector rhs) { //Code for adding two cartesian vectors. } //polar.d Vector opBinary(string op : +)(ref Vector lhs, ref Vector rhs) { //Code for adding two polar vectors. } //main.d import polar, vector; void main() { auto a = Vector(2, 5); auto b = Vector(4, 10); auto c = a + b; //What overload should we pick here? //This ambiguity could potentially be resolved like this: auto d = polar.opBinary!+(a, b); //But... This defeats the whole purpose of operators. } Interesting point. However, I believe this is also the case for ordinary functions used with UFCS: // cartesian.d Vector add(ref Vector lhs, ref Vector rhs) { /* Code for adding two cartesian vectors. */ } // polar.d Vector add(ref Vector lhs, ref Vector rhs) { /* Code for adding two polar vectors. */ } // main.d import polar, vector; void main() { auto a = Vector(2, 5); auto b = Vector(4, 10); auto c = a.add(b); // What overload should we pick here? // The fully qualified form looks quite different, // but it's rare, and intentionally explicit about what's // really going on, so that's OK. auto d = polar.add(a, b); } It strikes me that ambiguous cases are not nearly as common as unambiguous cases, especially if you use selective imports. I believe Julia uses a re-write rule for its operators: the first thing the compiler does when evaluating an operator expression is re-write it as a function call; after that, all the language's resolution rules apply as they would to any other function call. D could easily take this approach, simplifying the language while maintaining backwards-compatibility. Side note: You can achieve what you want to do with template mixins. ... While this implementation is not as clean as global operator overloading it works today and it makes it very simple to add operators to new types of grids. Thanks for the example. This is actually my current solution :) However, as you allude to, I'm not a huge fan of it because 1) It requires boilerplate on the part of library users. 2) It makes you scratch your head and go Huh; operator and non-operator functions have different compile-time polymorphism capabilities; why is that?
Re: Optionally strongly typed array indexes
Interesting idea. I run into these sorts of bugs often doing multimedia processing. There's definitely a tension between writing generic code (NumPy-style, operating on abstract dimensions) and safe code (operating on dimensions with semantics; OpenCV supports this to an extent). I've never used Ada so I may be missing the point, but here are my impressions: It seems to me that the users who may benefit most from this feature are likely to be using non-built-in data structures. For example, you mention interpreting the first level of array nesting as rows and the second as columns, implying you are treating the nested arrays as a matrix (rather than a list of lists, boxes of kittens, etc.). I'm inclined to believe use-cases for strongly-typed indices would often overlap with use-cases for strongly-typed containers. If that is true, then the language already provides decent support for annotating indices with units: /* Deep in the belly of some image-processing library... */ alias Row = Dimension!row; alias Column = Dimension!column; alias Channel = Dimension!channel; alias Image = DenseGrid!(ubyte, row column channel); /* In user code... */ Image image = drawPrettyPicture(); ubyte r = image[Row(0), Column(0), Channel(0)]; ubyte g = image[Row(0), Column(0), Channel(1)]; ubyte b = image[Row(0), Column(0), Channel(2)]; /* Or if you want to get really fancy... */ enum red = Channel(0), green = Channel(1), blue = Channel(2); ubyte r = image[Row(0), Column(0), red]; ubyte g = image[Row(0), Column(0), green]; ubyte b = image[Row(0), Column(0), blue]; /* Depending on how DenseGrid.opIndex is defined, these statements could fail to compile... */ image[Column(0), Row(0), red]; image[blue, Row(0), Column(0)]; Speculation: A good behavior for such a `DenseGrid.opIndex` might allow untyped (size_t) indices for generic algorithms and users who can't be bothered, but reject incorrectly-typed indices (e.g. a `BoxOfKittens` should not be indexed with a `Row`, just as an `Image` should not be indexed with a `CatName`.
Re: More useful fixed-size array literals
On Friday, 30 May 2014 at 22:19:51 UTC, bearophile wrote: A language solution is a literal syntax for fixed-sized arrays (here I slice it again because unfortunately count doesn't accept fixed-sized arrays): immutable data = [1, 5, 3, 1, 5, 1, 5]; void main() @nogc { import std.algorithm: count; assert(data.count([1, 5]s[]) == 3); } I would use this often. It's always seemed strange to me that static arrays are one of the few built-in data structures that don't have a dedicated literal form. `[1, 2, 3]s` nicely parallels the syntax for string and number literals.
Re: New syntax proposal for template type parameter contraints
On Saturday, 17 May 2014 at 01:53:46 UTC, Steven Schveighoffer wrote: A possible solution: template interface isInputRange(T, E) { .. No change in implementation .. } void myTemplateFunction(T : isInputRange!int)(T t) { } would basically change this into the equivalent of today's constraints. however, given that the template parameter is coupled with the constraint more directly, a better error message could be created, e.g. Type MyNonRangeType does not satisfy template interface isInputRange!int. I like this, but may I suggest a slightly different approach: to parallel structures, classes, interfaces, etc., concepts could be defined as nouns. This avoids the need to define dummy type parameters (T, above) and construct lvalues from them. It also sidesteps the awkward is-typeof-lambda idiom: static interface InputRange(E) { // This code must compile for any InputRange!E. bool empty = this.empty; E front = this.front; this.popFront(); } void f1(T : InputRange!int)(T) { } void f2(E, T : InputRange!E)(T) { } This parallels the existing (declarative) notion of template specialization. With this scheme, one could also overload concepts: static interface InputRange { static assert(is(typeof(this) InputRange!E, E)); } // For the common case in which we don't need to name // the element type: void f3(T : InputRange)(T) { }
Re: Abstract DDoc output for better document generation
On Saturday, 17 May 2014 at 18:03:53 UTC, Tolga Cakiroglu wrote: After having some experience with documentation generation from dmd command like, and seeing outputs, I wasn't satisfied with it. Other alternatives as Doxygen is available, though it parses codes itself that is not based on what version of DMD is installed on system. Since the structure of DDoc is already defined, instead of generating HTML output, I would propose to generate an XML file that contains meta data about codes and comments which can be used by 3rd party documentation generator programmes to generate HTML files. This way DDoc definitions can be simplified, better looking documents can be generated much easily. Try compiling with the -X flag to generate a JSON file describing the source. Add the -D flag if you want documentation comments in the JSON output. Hope that helps!
Re: Suggestion to implement __traits(getImports, Scope)
On Friday, 9 May 2014 at 04:09:46 UTC, captaindet wrote: by coincidence, i have use for this too. also thought __traits(allMembers, ...) would work. too bad it doesn't. is this a bug or expected behavior? /det Just out of curiosity, what's your use case?
Re: Julia vs. D?
On Tuesday, 6 May 2014 at 21:00:18 UTC, bearophile wrote: The language tries its best to be flexible as a dynamic language. But variables never carry a run-time type tag, unlike in Lisp. Hmm... Then how can I do this: x = 5 typeof(x) # evaluates to Int64 x = 5.0 typeof(x) # evaluates to Float64 ? Is Julia doing something trickier than I think it is? Or do you just mean they don't carry type tags after compilation?
Re: A Briefer Syntax for Using Concepts
On Wednesday, 7 May 2014 at 11:57:51 UTC, w0rp wrote: Here is a question, is it possible for D, or any future language, to eventually take something like this... void foo(InputRange)(InputRange range) if(isInputRange!InputRange); ...and to instead be able to write it like this? void foo(InputRange range); Where the latter expands into something like the former, and InputRange is not a type. How to declare such a thing in the first place doesn't matter that much. There are many ways that could be done. I'm just wondering if the above is possible at all. I think Julia does something like this, under the hood. Julia functions are instantiated once for every concrete argument type tuple they are invoked with: f(x) = x + 2 f(5) # Instantiation for Int64 f(5.0) # Instantiation for Float64 The assembly for these instantiations can be inspected by calling `code_native`. This works well for Julia because its runtime and type system are designed around being able to do this (JIT compilation, multiple dispatch, duck typing, immutable types). Programmers try to use run-time and compile-time polymorphism for the same thing: expressing operations on abstract types. But, each approach has its own advantage (CT: speed; RT: dynamic dispatch). I think the key insight is that the optimal implementation (RT vs. CT) depends only on how the generic function is used, not how it is defined. So, the choice of implementation can, in theory, be left up to a sufficiently-sophisticated runtime/JIT compiler. This seems to be what Julia has done (possibly along with some other Lispy languages; I'm not sure). However, this scheme can't entirely replace D-style templates (e.g. pattern matching). So, Julia still lets you define templates (which they call objects with static parameters). It would be great to have something like this in D (with compile-time semantics, of course).
Re: A new trait to retrieve doc comments (if available).
Thanks for the feedback! On Tuesday, 6 May 2014 at 07:41:20 UTC, bearophile wrote: Mason McGill: Other implementations can choose to always evaluate it to . Other implementations have to give the ddostring as well. Good to know! This will simplify the entry in the Traits documentation page. In D modules too have a ddoc string. Regarding comments on single variables, like this, I think they can be ignored for the moment, and added later with the same API if needed: int foo = 5; /// Not a string. It appears DMD already extracts module and variable comments. The JSON output for the following code associates all 3 comments with the appropriate symbols (compiled with dmd -D -X -o- test.d). /** * This is the test module. */ module test; const x = 5; /// This is x. /** * This is the main function. */ void main() {} So, it seems `__traits(comment, symbol)` should work for any symbol, at least the way I plan to implement it. This seems like the most useful behavior.
Re: Julia vs. D?
On Tuesday, 6 May 2014 at 11:28:21 UTC, Chris wrote: Maybe it's time to think about a D interface to Julia. If Julia catches on within the scientific community, it would be good to have a foot in the door. Science quickly creates large code bases, unfortunately, so far it's mostly Python and Matlab which makes it hard to use the algorithms in real world applications. I've actually been working on just that, on and off for a few months now. Such a thing is kind of anti-Julian, though, since one of Julia's main goals is to reduce or eliminate the need for mixed-language projects. However, with D, you can compile small shared libraries that can be automatically bound to your users' favorite dynamic runtimes (via compile-time reflection). I'm hoping this will be good for both D and Julia, allowing library developers to reach a broader audience, and library consumers greater flexibility. I'll post on the D announce thread when I have something working, and I'd definitely appreciate tests/bug-reports at that time!
Re: A new trait to retrieve doc comments (if available).
This is now a pull request: https://github.com/D-Programming-Language/dmd/pull/3531
A new trait to retrieve doc comments (if available).
**I'm fairly new to D, so let me know if this belongs in another thread.** I'd like to contribute a new feature to the DMD front-end, and I'd appreciate some feedback on the design before I start on a pull request. Feature: `__traits(comment, symbol)` will evaluate to the doc-comment of `symbol`, if it is available, and , otherwise. For DMD, this means it will provide comment information if the -D compiler option is used. Other implementations can choose to always evaluate it to . Use Cases: == Here's my use case: I'm building an automatic wrapper generator for binding D to dynamic languages (mostly for scientific applications, at the moment). It's like SWIG, but more automated and narrower in scope. Right now, I have two suboptimal options for supporting documentation comments: 1) Have users put their documentation in UDAs (instead of comments), and extract those. This means departing from D style guidelines, and that DDOC doesn't work. 2) Dig comments out of DMD's JSON output. This means users have to inform the wrapping tool of all of their D source files (not just a shared library), complicating build setups. It also means DMD loads and parses each file twice. Having doc-comments accessible at compile time would let me simplify the wrapping process for my users. Other applications include metaprogramming (e.g. forwarding documentation from a template argument) and simplifying documentation generators. I'm sure having doc-comments accessible in Python made things like Sphinx and IPython easier to build. Implementation: === I'm not too familiar with DMD, but it seems like evaluating `__traits(comment, symbol)` would just require reading out the relevant `DSymbol`'s `comment` field. Alternatives: = Alternative names: - `__traits(getComment, symbol)` - `__traits(documentation, symbol)` - `__traits(getDocumentation, symbol)` Alternative behaviors: - `__traits(comment, symbol)` could evaluate to `null` (rather than ) if there is no comment associated with `symbol`. Thoughts?