Re: Descent 0.5.5 released
For this release Robert Fraser made an excelent addition: when compiling programs using an external tool such as dsss, rebuild, dmd, gdc, ldc, gdmd or bud, there are now links to the files in the console output for warnings and errors. I think this one was pretty requested. So say thanks to him! :-) (here's a screenshot in case no one understood my poor English: http://downloads.dsource.org/projects/descent/problems.jpg :-P) 3
Re: Serialization for D. Comments, please!
Hello Brad, (moved from .announce to dm.D) BCS wrote: I'm planning on taking a crack at a Serialization template library and I'm looking for feed back. My thinking so far is up on my blog here: http://arrayboundserror.blogspot.com/2009/05/serialization-for-d-part -1-of-n.html Please comment! (here or there, doesn't matter, I think I'll see both) I strongly suggest figuring out early how you want to support multiple serialization formats. From experience, it's deceptively difficult to splice that into the design later. I'm already puzzling over that one g As for invocation, consider making the deserialization a constructor. The problem with making it a constructor is that it dosn't match with structs. I assume that in the example that the Deserialize method was static and acts as a factory? yes. Another point for you to ponder... do you want to support builtin types as a top level serialization point. ie, can you serialize a single int or must it be a struct or class or aggregate? If you _do_ want to support it, consider what will happen for formats that don't support it, such as xml and json. I was thinking it would end up as a string wrapped in a tag (for XML): int42/int
Re: OT: on IDEs and code writing on steroids
Lutger wrote: Yigal Chripun wrote: ... IMO, designing the language to support this better work-flow is a good decision made by MS, and D should follow it instead of trying to get away without an IDE. I'm not sure about this. D is designed to be easier to parse than C++ (but that's saying nothing) to allow better tools made for it. I think this should be enough. C# friends not only better supports working inside an IDE, but makes it a pain to do without. Autocomplete dictates that related functions should be named with the exact same prefix - even when this isn't logical. It also encourages names to be as descriptive as possible, in practice leading to a part of the api docs encoded in the function name. Extremely bloated names are the consequence of this. It doesn't always make code more readable imho. this I completely disagree with. those are the same faulty reasons I already answered. an IDE does _not_ create bad programmers, and does _not_ encourage bad code. it does encourage descriptive names which is a _good_ thing. writing strcpy ala C style is cryptic and *wrong*. code is read hundred times more than it's written and a better name would be for instance - stringCopy. it's common nowadays to have tera-byte sized HDD so why people try to save a few bytes from their source while sacrificing readability? the only issue I have with too long names is when dealing with C/C++ code that prefixes all symbols with their file-names/namespaces. At least in C++ this is solved by using namespaces. but this is a problem with the languages themselves and has nothing to do with the IDE. The documentation comments are in xml: pure insanity. I tried to generate documentation for my stuff at work once, expecting to be done in max 5 min. like ddoc. Turns out nobody at work uses documentation generation for a reason: it isn't really fleshed out and one-click from the IDE, in fact it is a pain in the arse compared to using ddoc. I should stop now before this turns into a rant. I agree fully with this. XML documents are a mistake made by MS. javadoc is a much better format and even that can be improved. This however has nothing to do with the IDE. the important part is that the IDE parses whatever format is used and can show you the documentation via simple means. no need for you to spend time to find the documentation yourself.
Re: OT: on IDEs and code writing on steroids
Andrei Alexandrescu wrote: ... What the heck do you need generics for when you have real templates? To me, generics seem like just a lame excuse for templates. I agree. Then, templates aren't easy to implement and they were understandably already busy implementing the using statement. Andrei While I don't fully understand how generics work under the hood in .NET, there are some benefits to how it is done. For example, you can use runtime reflection on generic types. And the jit compiler instantiates them at runtime. They may serve a different purpose than templates: Anders Hejlsberg: To me the best way to understand the distinction between C# generics and C++ templates is this: C# generics are really just like classes, except they have a type parameter. C++ templates are really just like macros, except they look like classes. It seems that lack of structural typing is seen as a feature: When you think about it, constraints are a pattern matching mechanism. You want to be able to say, This type parameter must have a constructor that takes two arguments, implement operator+, have this static method, has these two instance methods, etc. The question is, how complicated do you want this pattern matching mechanism to be? There's a whole continuum from nothing to grand pattern matching. We think it's too little to say nothing, and the grand pattern matching becomes very complicated, so we're in- between. From: http://www.artima.com/intv/genericsP.html
Re: OT: on IDEs and code writing on steroids
Andrei Alexandrescu wrote: ... I've repeatedly failed to figure out the coolness of C#, and would appreciate a few pointers. Or references. Or delegates :o). It's not in the language. C# only has to do 'better' than C++ and Java to be cool and in that it succeeds: Besides many smaller improvements, it provides delegates / events, lambda's and true generics compared to java. Compared to C++ it provides, well, lots of the same stuff that make people prefer Java over C++. It does this while still being familiar. Take F# for example, probably a much cooler language: I suspect this is too alien for most people. The real attraction of C# is the framework and the IDE. A lot of programmers don't program in a language, but in an ecosystem where the language is just a part of it alongside the framework, toolchain and documentation.
Re: Why is !() need with default template arguments
Jeremie Pelletier wrote: Jacob Carlborg Wrote: If I have a class like this: class Class (T = int) {} Then why can't I use it like this: auto c = new C; I have to do this: auto c = new C!(); I think it is so the parser knows how to make the difference between the template symbol and an instance symbol. Can you do anything with a template except instantiate it? -Lars
Re: Why is !() need with default template arguments
Lars T. Kyllingstad wrote: Can you do anything with a template except instantiate it? -Lars Pass it to another template as an alias argument. -- Daniel
Re: OT: on IDEs and code writing on steroids
On Wed, 20 May 2009 17:31:14 +1200, Jarrett Billingsley jarrett.billings...@gmail.com wrote: Just, uh, wow. Please dude, read up on this stuff first. This thread turned into a java vs .net argument. I'm sorry but I don't know the details of the JVM's just in time compiler. The virtual machine in the name plus the design goals led me to this misunderstanding It should be interpreted, threaded, and dynamic http://en.wikipedia.org/wiki/Java_(programming_language)#Primary_goals http://en.wikipedia.org/wiki/Comparison_of_the_Java_and_.NET_platforms
switch-case (bug, not a proposal)
Why can we do string s; switch(s) { case blah: break; default: } but not byte[] a; switch(a) { case [cast(byte)1,2,3]: break; default: } ?
Re: switch-case (bug, not a proposal)
heh: http://d.puremagic.com/issues/show_bug.cgi?id=596
Re: with should be deprecated with extreme prejudice
Nick Sabalausky wrote: Nick Sabalausky a...@a.a wrote in message news:guscm2$2jf...@digitalmars.com... Don nos...@nospam.com wrote in message news:gurkuo$17n...@digitalmars.com... Nick Sabalausky wrote: Don nos...@nospam.com wrote in message news:gur1ec$18...@digitalmars.com... If warnings exist, libraries must not do anything that creates a warning. They are NOT optional. That's only true if a compiler (such as DMD) is only capable of treating warnings as errors. No. Users complain if library code generates warnings. Because a user cannot make their code warning-free if the libraries they use are generating warnings. They can if they use a prebuilt version of the library, a lib/a/dll. Warnings are optional built-in lint tools (kinda like how we already have a built-in doc tool, built-in code generation tool (ie, mixins), built-in profiling/code-coverage, etc). And it's pretty difficult to claim that lint tools are bad. If they are standardised, they _are_ bad, because they become mandatory for libraries. If they're not standardised, no problem, it's just a third-party tool which you particular users find helpful in eliminating bugs; and demanding that a library support your third-party tool is unreasonable. Warnings can be categorised based on probability that they indicate a bug, with a range from: (1) it almost always indicates a bug -- in this case, it should be an error. (2) it hardly ever indicates a bug -- in this case, it's useless at best, but in practice it's harmful. If there's anything in between, it indicates a weakness in that part of the language design. DMD's warnings are now extremely close to (1), I hope they can become errors soon. (Eg, leaving off a return statement in a function which doesn't contain asm statements is almost guaranteed to be a bug).
Re: with still sucks + removing features + adding features
Christopher Wright: The more common suggestion is: alias bar = foo; I can add this too: typedef Bar = Foo; This changes in typedef and alias can solve two of the small problems I have with D. Let's see if Walter accepts such ideas. (In the last days two more ideas have floated in this newsgroup: disallowing floating point literals with nothing before the point like .57, and making with safer). Such small improvements pile up. Bye, bearophile
Re: OT: on IDEs and code writing on steroids
BCS Wrote: smaller object code? OTOH a good implementation will noice when I can fold together several template expansions That's the difference. You can't fold templates because they're binary incompatible as opposite to generics.
Re: OT: on IDEs and code writing on steroids
Kagamin wrote: BCS Wrote: smaller object code? OTOH a good implementation will noice when I can fold together several template expansions That's the difference. You can't fold templates because they're binary incompatible as opposite to generics. They're not always binary-incompatible. For instance, if a template only works with pointers or references (this includes object references) to parameter types it might well contain the exact same machine code for some of the instantiations. A compiler backend or linker could recognize these cases and use a single instantiation's machine code for them. (Essentially, these are pretty much the same cases where generics would have been sufficient)
Re: OT: on IDEs and code writing on steroids
On Wed, 20 May 2009 13:09:37 +0400, Kagamin s...@here.lot wrote: BCS Wrote: smaller object code? OTOH a good implementation will noice when I can fold together several template expansions That's the difference. You can't fold templates because they're binary incompatible as opposite to generics. You can fold /some/ templates. I believe LLVM already does merging of identical functions (including templates, virtual functions etc) as a part of optimization process. Not sure about LDC, though.
Re: Some memory safety
Walter Bright: Sorry for raising this thread. While C# has purposes somewhat different from D, I think C# designers are right in their emphasys on safety. Modern programmers appreciate some safeties, and modern languages give them. The ideas I am talking about are already implemented in C#. D can disable such safeties in release mode. For example this C# code, compiled in release + unsafe mode shows that the dotnet stops the execution almost as soon you write out of the allowed memory zone. This uses stackalloc (similar to alloca) so they may be using a stack canary to detect the out of bound condition at runtime: http://en.wikipedia.org/wiki/Stack_buffer_overflow#Stack_canaries using System; public sealed unsafe class Test { static void Main(string[] args) { int n = args.Length 0 ? Int32.Parse(args[0]) : 10; int* a = stackalloc int[n]; for (int i = 0; i n * 2; i++) { a[i] = i; Console.WriteLine({0}, a[i]); } } } D is not going to catch memory safety problems that result from using C library functions, like malloc. D can only guarantee memory safety when using D code and D library functions. The programmer is on his own using the unsafe C functions. When I port C code to D I'd like the D compiler help me catch some of the memory bugs that may be present in the translated C code. In C you have www.splint.org and valgrind, but the Java compiler shows how much good is to have a stricter compiler in the first place. And in D code you have array.ptr and std.gc.malloc too (and std.c.stdlib.alloca, that is a C function but has no equivalent to D, so I can think of it as part of D), such things may lead to bugs. Such things may be totally disallowed in safe D modules, but some safety may be added to unsafe D modules too. For example the memory std.gc.capacity() of Phobos1 can be used to detect out of bound situations with pointers given by std.gc.malloc. Bye, bearophile
Re: OT: on IDEs and code writing on steroids
Lutger lutger.blijdest...@gmail.com wrote in message news:gv090o$22...@digitalmars.com... Andrei Alexandrescu wrote: ... What the heck do you need generics for when you have real templates? To me, generics seem like just a lame excuse for templates. I agree. Then, templates aren't easy to implement and they were understandably already busy implementing the using statement. Andrei While I don't fully understand how generics work under the hood in .NET, there are some benefits to how it is done. For example, you can use runtime reflection on generic types. And the jit compiler instantiates them at runtime. They may serve a different purpose than templates: Anders Hejlsberg: To me the best way to understand the distinction between C# generics and C++ templates is this: C# generics are really just like classes, except they have a type parameter. C++ templates are really just like macros, except they look like classes. It seems that lack of structural typing is seen as a feature: When you think about it, constraints are a pattern matching mechanism. You want to be able to say, This type parameter must have a constructor that takes two arguments, implement operator+, have this static method, has these two instance methods, etc. The question is, how complicated do you want this pattern matching mechanism to be? There's a whole continuum from nothing to grand pattern matching. We think it's too little to say nothing, and the grand pattern matching becomes very complicated, so we're in- between. From: http://www.artima.com/intv/genericsP.html I can see certain potential benefits to the general way C# does generics, but until the old (and I do mean old) issue of There's an IComparable, so why the hell won't MS give us an IArithmetic so we can actually use arithmetic operators on generic code? gets fixed (and at this point I'm convinced they've never had any intent of ever fixing that), I don't care how valid the reasoning behind C#'s general approach to generics is, the actual state of C#'s generics still falls squarely into the categories of crap and almost useless.
Re: OT: on IDEs and code writing on steroids
Denis Koroskin wrote: On Wed, 20 May 2009 13:09:37 +0400, Kagamin s...@here.lot wrote: BCS Wrote: smaller object code? OTOH a good implementation will noice when I can fold together several template expansions That's the difference. You can't fold templates because they're binary incompatible as opposite to generics. You can fold /some/ templates. I believe LLVM already does merging of identical functions (including templates, virtual functions etc) as a part of optimization process. Not sure about LDC, though. LLVM has a function merging pass, but LDC doesn't run it by default at any optimization level. (You can pass -mergefunc to run it explicitly, as with any LLVM pass) It has some limitations though. Since it runs on IR, it matters what LLVM type values have. That means it might merge Templ!(int) and Templ!(uint) since int and uint are both an i32 to LLVM, but it normally wouldn't merge Templ!(int*) and Templ(short*) even if the template compiles down to return cast(T) somefunc(cast(void*) arg); because the types are still different (i32* vs i16*). To do the latter transformation, the pass would need to be reimplemented to run when the code is closer to machine code.
Re: Why is !() need with default template arguments
On Wed, 20 May 2009 15:01:44 +1200, Jeremie Pelletier jerem...@gmail.com wrote: I think it is so the parser knows how to make the difference between the template symbol and an instance symbol. Can you explain a bit more on this? function templates dont require this by the way and I didn't think a template could ever be 'newed'
Re: OT: on IDEs and code writing on steroids
dsimcha escribió: == Quote from Christopher Wright (dhase...@gmail.com)'s article Nick Sabalausky wrote: Andrei Alexandrescu seewebsiteforem...@erdani.org wrote in message news:gus0lu$1sm...@digitalmars.com... I've repeatedly failed to figure out the coolness of C#, and would appreciate a few pointers. Or references. Or delegates :o). Outside of this group, I think most of the people considering C# really cool are people who are unaware of D and are coming to C# from Java. What's cool about C# is that it's like a less-shitty version of Java (and *had* good tools, although the newer versions of VS are almost as much of a bloated unresponsive mess as Eclipse - Which come to think of it, makes me wonder - If Java has gotten so fast as many people claim, why is Eclipse still such a sluggish POS?). Compare C# to D though and most of the coolness fades, even though there are still a handful of things I think D could still learn from C# (but there's probably more than a handful that C# could learn from D). Generics and reflection. Generics just hide a lot of casts, usually, but that's still quite useful. And autoboxing is convenient, though not appropriate for D. What the heck do you need generics for when you have real templates? To me, generics seem like just a lame excuse for templates. Yesterday doob reported a bug in Descent saying when you compile your project and it references a user library that has errors, when you click on the console to jump to the error, it doesn't work. I said to him: I never thought a user library could have errors! How did this happen to you? He replied: I found a bug in a template in Tango. That's why generics doesn't suck: if there's something wrong in them, the compiler tells you in compile-time. In D, you get the errors only when instantiating that template. Generics might not be as powerful as templates, but once you write one that compiles, you know you will always be able to instantiate it.
Re: OT: on IDEs and code writing on steroids
Ary Borenszweig: That's why generics doesn't suck: if there's something wrong in them, the compiler tells you in compile-time. In D, you get the errors only when instantiating that template. It's just like in dynamic languages, you need to unittest them a lot :-) So having a static throws() to assert that a template isn't working is very useful. Bye, bearophile
Re: OT: on IDEs and code writing on steroids
Nick Sabalausky wrote: I can see certain potential benefits to the general way C# does generics, but until the old (and I do mean old) issue of There's an IComparable, so why the hell won't MS give us an IArithmetic so we can actually use arithmetic operators on generic code? gets fixed (and at this point I'm convinced they've never had any intent of ever fixing that), I don't care how valid the reasoning behind C#'s general approach to generics is, the actual state of C#'s generics still falls squarely into the categories of crap and almost useless. IArithmetic is impossible in C# because operator overloads are static methods, and interfaces cannot specify static methods.
Re: OT: on IDEs and code writing on steroids
Frits van Bommel: To do the latter transformation, the pass would need to be reimplemented to run when the code is closer to machine code. Can't this feature be asked to the LLVM developers? Bye, bearophile
Re: OT: on IDEs and code writing on steroids
dsimcha wrote: == Quote from Christopher Wright (dhase...@gmail.com)'s article Nick Sabalausky wrote: Andrei Alexandrescu seewebsiteforem...@erdani.org wrote in message news:gus0lu$1sm...@digitalmars.com... I've repeatedly failed to figure out the coolness of C#, and would appreciate a few pointers. Or references. Or delegates :o). Outside of this group, I think most of the people considering C# really cool are people who are unaware of D and are coming to C# from Java. What's cool about C# is that it's like a less-shitty version of Java (and *had* good tools, although the newer versions of VS are almost as much of a bloated unresponsive mess as Eclipse - Which come to think of it, makes me wonder - If Java has gotten so fast as many people claim, why is Eclipse still such a sluggish POS?). Compare C# to D though and most of the coolness fades, even though there are still a handful of things I think D could still learn from C# (but there's probably more than a handful that C# could learn from D). Generics and reflection. Generics just hide a lot of casts, usually, but that's still quite useful. And autoboxing is convenient, though not appropriate for D. What the heck do you need generics for when you have real templates? To me, generics seem like just a lame excuse for templates. Put a template in an interface. Use reflection to instantiate a template.
Re: OT: on IDEs and code writing on steroids
bearophile wrote: Frits van Bommel: To do the latter transformation, the pass would need to be reimplemented to run when the code is closer to machine code. Can't this feature be asked to the LLVM developers? Sure, feel free to file a feature request: http://llvm.org/bugs/enter_bug.cgi?product=new-bugs
Re: with still sucks + removing features + adding features
Andrei Alexandrescu wrote: Robert Fraser wrote: Frank Benoit wrote: Alexander Pánek schrieb: Andrei Alexandrescu wrote: bearophile wrote: Andrei Alexandrescu: Thank you for bringing a real example that gives something to work on. Awful! Well, one of your cases was wrong. Using the +1 at the end one of those cases become: case 'A' .. 'Z'+1, 'a' .. 'z'+1: Instead of what you have written: case 'A' .. 'Z'+1: case 'a' .. 'z'+1: I agree that that syntax with +1 isn't very nice looking. But the advantage of +1 is that it introduces (almost) no new syntax, it's not easy to miss, its meaning is easy to understand. AND you don't have to remember that in a case the .. is inclusive while in foreach is exclusive on the right, keeping the standard way in D to denote ranges. You don't understand. My point is not that people will dislike 'Z'+1. They will FORGET TO WRITE THE BLESSED +1. They'll write: case 'A' .. 'Z': You know, Ruby solves this by introducing a “seperate” range syntax for exclusive ranges: “...”. An inclusive range is written the same as an exclusive range in D: “..”. a[1 .. 2].length #= 1 ([a[1]]) a[1 ... 2].length #= 2 ([a[1], a[2]]) I see no reason not to include such a seperate syntax in D. “..” being exclusive and “...” being inclusive, not the other way round as in Ruby — see “Programmer’s Paradox” @ http://www.programmersparadox.com/2009/01/11/ruby-range-mnemonic/ . Kind regards, Alex Yes, this is useful for all use cases of ranges. I like '...'. Indeed it's not a bad idea... But it might be easily mistyped, lead to strange off-by-one errors and be very difficult to find while debugging them. Hmmm... It's an awful idea. It's a non-idea. If idea had an antonym, that would be it. I can't fathom what's on the mind of a person (not you, at least you foresee some potential problems) who, even after patiently explained the issues with this mental misfire, several times, still can bring themselves to think it's not that bad. I don’t see a reason not to restrict other features to introduce a new one. I never used .foo to access the global scope or .1 for floating point literals. But what I do use very often is array[n..m + 1], which would ease things for quite a lot of things going on when working with arrays. Of course it’s just syntactic sugar, but so is the whole slicing feature. It could easily be done in the standard library. So I’m not demanding anything, I’m just providing my very own thoughts on this topic. If there are too many obstacles then it’s probably not worth it. The thing is, I don’t know half as much as most of the guys here do, so I don’t see those obstacles at first glance. Please bear with me. :) Let me add one more, although more than sure someone will find a remedy for it, too. a...b inclusive range from a to b vs. a.. .b exclusive range from a to .b Personally, I see “...” as an atomic operator, like “!=” or “==”. I wouldn’t ever recognize “.. .” as “...” or “! =” as “!=”. Additionally, I add a space before and after every operator, so there’s no ambiguity in any way, plus it’s nicely recognizable what the hell is going on. If it was for me, I’d even go as far as to make this a requirement in the specification. But that would upset downs. Actually, what about “…” as inclusive range operator? :P I’d love that. and of course the beauty ab Inclusive range from “a” to “.b”? Pretty clear in this *particular* case. ;) I don't plan to discuss minor features on this group anymore. But.. bike shed discussions are fun! Seriously, though — I learn a lot thanks to people “nitpicking” other people’s ideas, showing corner cases, obstacles and so on. So please, don’t stop discussing minor features. :)
Re: with still sucks + removing features + adding features
bearophile wrote: Christopher Wright: The more common suggestion is: alias bar = foo; I can add this too: typedef Bar = Foo; This changes in typedef and alias can solve two of the small problems I have with D. Let's see if Walter accepts such ideas. (In the last days two more ideas have floated in this newsgroup: disallowing floating point literals with nothing before the point like .57, and making with safer). Such small improvements pile up. Bye, bearophile typedef int MyInt = 1;
Re: with still sucks + removing features + adding features
On Wed, 20 May 2009 00:43:56 +0400, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: It's an awful idea. It's a non-idea. If idea had an antonym, that would be it. I can't fathom what's on the mind of a person (not you, at least you foresee some potential problems) who, even after patiently explained the issues with this mental misfire, several times, still can bring themselves to think it's not that bad. Your post is emotional rather than rational. Let me add one more, although more than sure someone will find a remedy for it, too. a...b vs. a.. .b a..b vs a.b - no one complains It also gracefully solves an issue with uniform distribution uniform(0..int.max) - exclusive uniform(0...int.max) - inclusive (can't be replaced with 0..int.max+1) also in switch: switch(a) { case 0..10: // exclusive case 10...100: // inclusive } I don't plan to discuss minor features on this group anymore. It is as minor as case a: .. case b:, i.e. not minor at all. I'd say that there is no such thing as minor feature, every feature is important. Andrei
Re: Why is !() need with default template arguments
Tim Matthews Wrote: On Wed, 20 May 2009 15:01:44 +1200, Jeremie Pelletier jerem...@gmail.com wrote: I think it is so the parser knows how to make the difference between the template symbol and an instance symbol. Can you explain a bit more on this? function templates dont require this by the way and I didn't think a template could ever be 'newed' Oh yeah you are right, it has already been filed as a bug.
Re: OT: on IDEs and code writing on steroids
== Quote from Ary Borenszweig (a...@esperanto.org.ar)'s article dsimcha escribió: == Quote from Christopher Wright (dhase...@gmail.com)'s article Nick Sabalausky wrote: Andrei Alexandrescu seewebsiteforem...@erdani.org wrote in message news:gus0lu$1sm...@digitalmars.com... I've repeatedly failed to figure out the coolness of C#, and would appreciate a few pointers. Or references. Or delegates :o). Outside of this group, I think most of the people considering C# really cool are people who are unaware of D and are coming to C# from Java. What's cool about C# is that it's like a less-shitty version of Java (and *had* good tools, although the newer versions of VS are almost as much of a bloated unresponsive mess as Eclipse - Which come to think of it, makes me wonder - If Java has gotten so fast as many people claim, why is Eclipse still such a sluggish POS?). Compare C# to D though and most of the coolness fades, even though there are still a handful of things I think D could still learn from C# (but there's probably more than a handful that C# could learn from D). Generics and reflection. Generics just hide a lot of casts, usually, but that's still quite useful. And autoboxing is convenient, though not appropriate for D. What the heck do you need generics for when you have real templates? To me, generics seem like just a lame excuse for templates. Yesterday doob reported a bug in Descent saying when you compile your project and it references a user library that has errors, when you click on the console to jump to the error, it doesn't work. I said to him: I never thought a user library could have errors! How did this happen to you? He replied: I found a bug in a template in Tango. That's why generics doesn't suck: if there's something wrong in them, the compiler tells you in compile-time. In D, you get the errors only when instantiating that template. Generics might not be as powerful as templates, but once you write one that compiles, you know you will always be able to instantiate it. Yes, but there are two flaws in this argument: 1. If you are only using templates like generics, you simply use a unit test to see if it compiles. If you're not doing anything fancy and it compiles for one or two types, it will probably compile for everything that you would reasonably expect it to. 2. If you're doing something fancier, like metaprogramming, you have to just face the fact that this is non-trivial, and couldn't be done with generics anyhow. 3. As Bearophile alluded to, templates are really a clever hack to give you the flexibility of a dynamic language with the performance and compile time checking of a static language. This is done by moving the dynamism to instantiation time. Therefore, whereas in a dynamic language you pay at runtime in terms of the here be monsters, this code may not be being used as the author intended and tested it, with templates you pay at instantiation time. However, IMHO this is orders of magnitude better than not having that flexibility at all. I personally can't figure out how people accomplish anything in static languages w/o templates. It's just too inflexible.
Re: with still sucks + removing features + adding features
bearophile Wrote: Andrei Alexandrescu: I don't plan to discuss minor features on this group anymore. That's a real pity. I had a lot of respect for you and your perpetual inclusion of the D community (both announcing features and getting design feedback). Very early on in this thread, it became obvious to me that too much of it was getting under your skin. I've lost count of the insults posted in this thread. We're all trying to make D the best language we can, even if we come from vastly different perspectives.
Re: OT: on IDEs and code writing on steroids
Lutger wrote: Andrei Alexandrescu wrote: ... What the heck do you need generics for when you have real templates? To me, generics seem like just a lame excuse for templates. I agree. Then, templates aren't easy to implement and they were understandably already busy implementing the using statement. Andrei While I don't fully understand how generics work under the hood in .NET, there are some benefits to how it is done. For example, you can use runtime reflection on generic types. And the jit compiler instantiates them at runtime. They may serve a different purpose than templates: Anders Hejlsberg: To me the best way to understand the distinction between C# generics and C++ templates is this: C# generics are really just like classes, except they have a type parameter. C++ templates are really just like macros, except they look like classes. It seems that lack of structural typing is seen as a feature: When you think about it, constraints are a pattern matching mechanism. You want to be able to say, This type parameter must have a constructor that takes two arguments, implement operator+, have this static method, has these two instance methods, etc. The question is, how complicated do you want this pattern matching mechanism to be? There's a whole continuum from nothing to grand pattern matching. We think it's too little to say nothing, and the grand pattern matching becomes very complicated, so we're in- between. From: http://www.artima.com/intv/genericsP.html Oh, so Wal^H^H^Ha friend of mine I was talking to was right: there's some missing of the point point going on. The code generation aspect of templates is a blind spot of the size of Canada. Andrei
Re: with still sucks + removing features + adding features
Denis Koroskin wrote: On Wed, 20 May 2009 00:43:56 +0400, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: It's an awful idea. It's a non-idea. If idea had an antonym, that would be it. I can't fathom what's on the mind of a person (not you, at least you foresee some potential problems) who, even after patiently explained the issues with this mental misfire, several times, still can bring themselves to think it's not that bad. Your post is emotional rather than rational. Agreed. In my defense, let me mention that I've been rational in my previous 50 posts on the topic :o). Let me add one more, although more than sure someone will find a remedy for it, too. a...b vs. a.. .b a..b vs a.b - no one complains You see, you didn't understand my point. My point was that the introduction of a space changes semantics. We should avoid that. It also gracefully solves an issue with uniform distribution uniform(0..int.max) - exclusive uniform(0...int.max) - inclusive (can't be replaced with 0..int.max+1) Yeah, and this does something else: uniform(0int.max) and if you use an alias we also have: uniform(0.A.max) It's interesting how there is a continuum of number of . that still lead to compilable code that does different things every time. Perfect material for Why D is a horrible language articles. Andrei
Re: with still sucks + removing features + adding features
Andrei Alexandrescu wrote: Denis Koroskin wrote: On Wed, 20 May 2009 00:43:56 +0400, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: It's an awful idea. It's a non-idea. If idea had an antonym, that would be it. I can't fathom what's on the mind of a person (not you, at least you foresee some potential problems) who, even after patiently explained the issues with this mental misfire, several times, still can bring themselves to think it's not that bad. Your post is emotional rather than rational. Agreed. In my defense, let me mention that I've been rational in my previous 50 posts on the topic :o). Let me add one more, although more than sure someone will find a remedy for it, too. a...b vs. a.. .b a..b vs a.b - no one complains You see, you didn't understand my point. My point was that the introduction of a space changes semantics. We should avoid that. It also gracefully solves an issue with uniform distribution uniform(0..int.max) - exclusive uniform(0...int.max) - inclusive (can't be replaced with 0..int.max+1) Yeah, and this does something else: uniform(0int.max) and if you use an alias we also have: uniform(0.A.max) It's interesting how there is a continuum of number of . that still lead to compilable code that does different things every time. Perfect material for Why D is a horrible language articles. This is easily solved by making the lexer not allow the token, or . token, etc. (maximum 3 dots.) This way you are forced to insert a space there to make your intention clear, and you can never have bugs like that. Perfect material for Why D is a beautiful language articles.
Re: with still sucks + removing features + adding features
Ary Borenszweig wrote: This is easily solved by making the lexer not allow the token, or . token, etc. (maximum 3 dots.) This way you are forced to insert a space there to make your intention clear, and you can never have bugs like that. I agree that things could be fixed. This is, however, a hack because a lexer is not supposed to operate that way. Lexers are maximum munch. So we're looking at a number of problems here. One is that we'd need to change the language in several places to accommodate an ill-conceived feature. Another is that I can't seem to get some very simple points across such as the difference between a token and a non-terminal, in spite of having tried repeatedly and in various forms. Another is that I am becoming suffocated with self-righteousness and therefore am losing goodwill in this thread at an exponentially-increasing rate. Finally, it looks like such discussions necessitate more than a full-time job. Andrei
Re: with still sucks + removing features + adding features
Denis Koroskin: It also gracefully solves an issue with uniform distribution uniform(0..int.max) - exclusive uniform(0...int.max) - inclusive (can't be replaced with 0..int.max+1) To avoid the possible confusion caused by ... Chapel uses ..# uniform(0 .. int.max) - exclusive uniform(0 ..# int.max) - inclusive Bye, bearophile
Re: with still sucks + removing features + adding features
On Wed, May 20, 2009 at 7:28 AM, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: Denis Koroskin wrote: On Wed, 20 May 2009 00:43:56 +0400, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: It's an awful idea. It's a non-idea. If idea had an antonym, that would be it. I can't fathom what's on the mind of a person (not you, at least you foresee some potential problems) who, even after patiently explained the issues with this mental misfire, several times, still can bring themselves to think it's not that bad. Your post is emotional rather than rational. Agreed. In my defense, let me mention that I've been rational in my previous 50 posts on the topic :o). Let me add one more, although more than sure someone will find a remedy for it, too. a...b vs. a.. .b a..b vs a.b - no one complains You see, you didn't understand my point. My point was that the introduction of a space changes semantics. We should avoid that. It also gracefully solves an issue with uniform distribution uniform(0..int.max) - exclusive uniform(0...int.max) - inclusive (can't be replaced with 0..int.max+1) Yeah, and this does something else: uniform(0int.max) and if you use an alias we also have: uniform(0.A.max) It's interesting how there is a continuum of number of . that still lead to compilable code that does different things every time. Perfect material for Why D is a horrible language articles. Isn't 0...a already a horrendously awful non-idea and mental misfire by these arguments? --bb
Re: with still sucks + removing features + adding features
Andrei Alexandrescu wrote: Denis Koroskin wrote: On Wed, 20 May 2009 00:43:56 +0400, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: It's an awful idea. It's a non-idea. If idea had an antonym, that would be it. I can't fathom what's on the mind of a person (not you, at least you foresee some potential problems) who, even after patiently explained the issues with this mental misfire, several times, still can bring themselves to think it's not that bad. Your post is emotional rather than rational. Agreed. In my defense, let me mention that I've been rational in my previous 50 posts on the topic :o). Let me add one more, although more than sure someone will find a remedy for it, too. a...b vs. a.. .b a..b vs a.b - no one complains You see, you didn't understand my point. My point was that the introduction of a space changes semantics. We should avoid that. Like, a- --b vs. a-- -b ? It also gracefully solves an issue with uniform distribution uniform(0..int.max) - exclusive uniform(0...int.max) - inclusive (can't be replaced with 0..int.max+1) Yeah, and this does something else: uniform(0int.max) and if you use an alias we also have: uniform(0.A.max) It's interesting how there is a continuum of number of . that still lead to compilable code that does different things every time. Perfect material for Why D is a horrible language articles. Andrei
Re: with still sucks + removing features + adding features
Bill Baxter wrote: On Wed, May 20, 2009 at 7:28 AM, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: Denis Koroskin wrote: On Wed, 20 May 2009 00:43:56 +0400, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: It's an awful idea. It's a non-idea. If idea had an antonym, that would be it. I can't fathom what's on the mind of a person (not you, at least you foresee some potential problems) who, even after patiently explained the issues with this mental misfire, several times, still can bring themselves to think it's not that bad. Your post is emotional rather than rational. Agreed. In my defense, let me mention that I've been rational in my previous 50 posts on the topic :o). Let me add one more, although more than sure someone will find a remedy for it, too. a...b vs. a.. .b a..b vs a.b - no one complains You see, you didn't understand my point. My point was that the introduction of a space changes semantics. We should avoid that. It also gracefully solves an issue with uniform distribution uniform(0..int.max) - exclusive uniform(0...int.max) - inclusive (can't be replaced with 0..int.max+1) Yeah, and this does something else: uniform(0int.max) and if you use an alias we also have: uniform(0.A.max) It's interesting how there is a continuum of number of . that still lead to compilable code that does different things every time. Perfect material for Why D is a horrible language articles. Isn't 0...a already a horrendously awful non-idea and mental misfire by these arguments? --bb The problems increase exponentially with the number of dots. Andrei
Re: with still sucks + removing features + adding features
Jason House wrote: bearophile Wrote: Andrei Alexandrescu: I don't plan to discuss minor features on this group anymore. That's a real pity. I had a lot of respect for you and your perpetual inclusion of the D community (both announcing features and getting design feedback). Very early on in this thread, it became obvious to me that too much of it was getting under your skin. I've lost count of the insults posted in this thread. We're all trying to make D the best language we can, even if we come from vastly different perspectives. I am sorry I have gotten on the wrong side of civility in this thread. Andrei
Re: the last change for ranges
Robert Jacques wrote: Bicycle shed: Well, since output ranges use 'put', how about 'get' for input ranges? Nice color :o). In fact, put is a poor choice because it doesn't reflect advancement. Probably putNext and getNext are better. Andrei
Re: the last change for ranges
Bill Baxter wrote: On Wed, May 20, 2009 at 9:19 AM, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: I'm thinking a better design is to require any range that's forward or better to define a function save(). Ranges that don't implement it are input ranges; those that do, will guarantee a brand new range is returned from save(). So then adjacentFind would look like this: R adjacentFind(R)(R r) { if (r,empty) return r; R last = r.save; r.popFront; for (; !r.empty last.front != r.front; last.popFront, r.popFront) { } return r; } Obviously, when you pass a range that doesn't support save, adjacentFind will not compile, which is what we want. The only other alternative that comes to mind would be forcing input ranges to hide their copy constructor, or whatever the D equivalent is, making R last = r; fail. But that would make input ranges very difficult to use. Exactly. I thought of that design, and it was difficult to even pass a range to a function. So, of those two options at least, requiring a .save sounds like the better choice. The down side is you will get no error if you write the code the first way, without a .save. I see this as turning into tip #5 in Effective D -- Know when to use .save It would be nice if that potential mistake could be eliminated somehow. You could perhaps require input ranges to implement transfer semantics, and have them implement a .clone for cases when you really do want to make an aliasing copy. Good point. I don't have a solution for that. Giving ranges move semantics would probably make for another Effective D tip (or perhaps more... move semantics are pretty brutal). Another partial solution is to define a different interface for input ranges, one that combines front() and popFront(). Something like popNext. That way, people who use only the primitives empty() and popNext() know they are using a forward range and with hope they'll remember they can't really save copies of it and expect them to remember where they are in the input. Andrei
Re: the last change for ranges
== Quote from Andrei Alexandrescu (seewebsiteforem...@erdani.org)'s article In wake of a few discussion I've witnessed, I'm thinking of a last change for ranges. (In fact there's one more, but that's minor.) The problem is that input ranges and forward ranges have the same syntactic interface, but different semantic interfaces. Consider the problem of finding the first two identical adjacent items in a range: R adjacentFind(R)(R r) { if (r,empty) return r; R last = r; r.popFront; for (; !r.empty last.front != r.front; last.popFront, r.popFront) { } return r; } This will work properly on lists and vectors, but horrendously on files and sockets. This is because input ranges can't be saved for later use: incrementing r also increments popFront and essentially forces both to look at the same current value. I'm thinking a better design is to require any range that's forward or better to define a function save(). Ranges that don't implement it are input ranges; those that do, will guarantee a brand new range is returned from save(). So then adjacentFind would look like this: R adjacentFind(R)(R r) { if (r,empty) return r; R last = r.save; r.popFront; for (; !r.empty last.front != r.front; last.popFront, r.popFront) { } return r; } Obviously, when you pass a range that doesn't support save, adjacentFind will not compile, which is what we want. Andrei P.S. There is a way to implement adjacentFind for forward ranges by saving data instead of ranges. I've used a limited version above for illustration purposes. Sounds like at least a reasonable solution. The thing I like about it is that, in addition to safety, it allows for the range to do fancy and arbitrary stuff under the hood if necessary to allow for saving. Also, while we're fine tuning input ranges vs. forward ranges, I think the concept of iterables as a catch-all for ranges, opApply, builtins, etc. needs to be introduced and fine tuned, too. We've shown on this NG previously that, while ranges are usually preferable for the flexibility they offer, opApply does have its legitimate use cases.
Re: OT: on IDEs and code writing on steroids
Kagamin wrote: Frits van Bommel Wrote: That's the difference. You can't fold templates because they're binary incompatible as opposite to generics. They're not always binary-incompatible. For instance, if a template only works with pointers or references (this includes object references) to parameter types it might well contain the exact same machine code for some of the instantiations. If you require that the class inherits some interface and call that interface's methods, they'll be incompatible. I'll dare to say this is the most useful variant of generic code. Okay, so it doesn't (usually) work for interfaces, but it'll work if the requirement is for a common base class. Or perhaps even if they happen to have a common base class that implements the interface in question.
the last change for ranges
In wake of a few discussion I've witnessed, I'm thinking of a last change for ranges. (In fact there's one more, but that's minor.) The problem is that input ranges and forward ranges have the same syntactic interface, but different semantic interfaces. Consider the problem of finding the first two identical adjacent items in a range: R adjacentFind(R)(R r) { if (r,empty) return r; R last = r; r.popFront; for (; !r.empty last.front != r.front; last.popFront, r.popFront) { } return r; } This will work properly on lists and vectors, but horrendously on files and sockets. This is because input ranges can't be saved for later use: incrementing r also increments popFront and essentially forces both to look at the same current value. I'm thinking a better design is to require any range that's forward or better to define a function save(). Ranges that don't implement it are input ranges; those that do, will guarantee a brand new range is returned from save(). So then adjacentFind would look like this: R adjacentFind(R)(R r) { if (r,empty) return r; R last = r.save; r.popFront; for (; !r.empty last.front != r.front; last.popFront, r.popFront) { } return r; } Obviously, when you pass a range that doesn't support save, adjacentFind will not compile, which is what we want. Andrei P.S. There is a way to implement adjacentFind for forward ranges by saving data instead of ranges. I've used a limited version above for illustration purposes.
Re: OT: on IDEs and code writing on steroids
Frits van Bommel Wrote: That's the difference. You can't fold templates because they're binary incompatible as opposite to generics. They're not always binary-incompatible. For instance, if a template only works with pointers or references (this includes object references) to parameter types it might well contain the exact same machine code for some of the instantiations. If you require that the class inherits some interface and call that interface's methods, they'll be incompatible. I'll dare to say this is the most useful variant of generic code.
Re: the last change for ranges
I feel like there are too many differences between input and forward ranges for such a minor difference. Many range functions are written assuming no side effects on the caller. This can restrict the use of helper functions. It may be best to make their usage different... Andrei Alexandrescu Wrote: In wake of a few discussion I've witnessed, I'm thinking of a last change for ranges. (In fact there's one more, but that's minor.) The problem is that input ranges and forward ranges have the same syntactic interface, but different semantic interfaces. Consider the problem of finding the first two identical adjacent items in a range: R adjacentFind(R)(R r) { if (r,empty) return r; R last = r; r.popFront; for (; !r.empty last.front != r.front; last.popFront, r.popFront) { } return r; } This will work properly on lists and vectors, but horrendously on files and sockets. This is because input ranges can't be saved for later use: incrementing r also increments popFront and essentially forces both to look at the same current value. I'm thinking a better design is to require any range that's forward or better to define a function save(). Ranges that don't implement it are input ranges; those that do, will guarantee a brand new range is returned from save(). So then adjacentFind would look like this: R adjacentFind(R)(R r) { if (r,empty) return r; R last = r.save; r.popFront; for (; !r.empty last.front != r.front; last.popFront, r.popFront) { } return r; } Obviously, when you pass a range that doesn't support save, adjacentFind will not compile, which is what we want. Andrei P.S. There is a way to implement adjacentFind for forward ranges by saving data instead of ranges. I've used a limited version above for illustration purposes.
Re: the last change for ranges
On Wed, 20 May 2009 20:23:27 +0400, Denis Koroskin 2kor...@gmail.com wrote: On Wed, 20 May 2009 20:19:30 +0400, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: In wake of a few discussion I've witnessed, I'm thinking of a last change for ranges. (In fact there's one more, but that's minor.) The problem is that input ranges and forward ranges have the same syntactic interface, but different semantic interfaces. Consider the problem of finding the first two identical adjacent items in a range: R adjacentFind(R)(R r) { if (r,empty) return r; R last = r; r.popFront; for (; !r.empty last.front != r.front; last.popFront, r.popFront) { } return r; } This will work properly on lists and vectors, but horrendously on files and sockets. This is because input ranges can't be saved for later use: incrementing r also increments popFront and essentially forces both to look at the same current value. I'm thinking a better design is to require any range that's forward or better to define a function save(). Ranges that don't implement it are input ranges; those that do, will guarantee a brand new range is returned from save(). So then adjacentFind would look like this: R adjacentFind(R)(R r) { if (r,empty) return r; R last = r.save; r.popFront; for (; !r.empty last.front != r.front; last.popFront, r.popFront) { } return r; } Obviously, when you pass a range that doesn't support save, adjacentFind will not compile, which is what we want. Andrei P.S. There is a way to implement adjacentFind for forward ranges by saving data instead of ranges. I've used a limited version above for illustration purposes. Why not r.dup? Nevermind, I don't want to turn it into a bycicle shed discussion, but .dup would be consistent with arrays. Do you suggest that ranges now have a reference semantics? That's quite a big change, but I do believe that it's for good, because it make classes a rightful ranges citizen.
Re: with still sucks + removing features + adding features
KennyTM~ wrote: Andrei Alexandrescu wrote: Denis Koroskin wrote: On Wed, 20 May 2009 00:43:56 +0400, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: It's an awful idea. It's a non-idea. If idea had an antonym, that would be it. I can't fathom what's on the mind of a person (not you, at least you foresee some potential problems) who, even after patiently explained the issues with this mental misfire, several times, still can bring themselves to think it's not that bad. Your post is emotional rather than rational. Agreed. In my defense, let me mention that I've been rational in my previous 50 posts on the topic :o). Let me add one more, although more than sure someone will find a remedy for it, too. a...b vs. a.. .b a..b vs a.b - no one complains You see, you didn't understand my point. My point was that the introduction of a space changes semantics. We should avoid that. Like, a- --b vs. a-- -b ? Yes, like that. I didn't say there aren't any right now. I said we should avoid that. Andrei
Re: the last change for ranges
dsimcha wrote: Also, while we're fine tuning input ranges vs. forward ranges, I think the concept of iterables as a catch-all for ranges, opApply, builtins, etc. needs to be introduced and fine tuned, too. We've shown on this NG previously that, while ranges are usually preferable for the flexibility they offer, opApply does have its legitimate use cases. An input/forward range is basically just another name/syntax for an iterable. Perhaps algorithms that work on input ranges should be written using foreach instead of front/popFront?
Re: the last change for ranges
Robert Fraser wrote: dsimcha wrote: Also, while we're fine tuning input ranges vs. forward ranges, I think the concept of iterables as a catch-all for ranges, opApply, builtins, etc. needs to be introduced and fine tuned, too. We've shown on this NG previously that, while ranges are usually preferable for the flexibility they offer, opApply does have its legitimate use cases. An input/forward range is basically just another name/syntax for an iterable. Perhaps algorithms that work on input ranges should be written using foreach instead of front/popFront? For most, foreach is not sufficient. Andrei
Re: the last change for ranges
== Quote from Denis Koroskin (2kor...@gmail.com)'s article Why not r.dup? .dup is supposed to imply copying of the range's contents, not copying of the range's iteration state.
Re: the last change for ranges
Jason House wrote: Andrei Alexandrescu Wrote: Jason House wrote: I feel like there are too many differences between input and forward ranges for such a minor difference. Many range functions are written assuming no side effects on the caller. This can restrict the use of helper functions. It may be best to make their usage different... So how do you think we should go about it? Also don't forget that any ranges should be seamlessly and efficiently treated as input ranges. Andrei You won't like my answer! Like you've already said, the semantics of forward ranges and input ranges are different. I would argue that forward ranges have value semantics but input ranges do not. Any function that implicitly assumes value semantics is wrong. Sadly, overlapping API's makes that all too easy for someone to write bad code that passes simplistic tests with forward ranges and then fail with input ranges. My initial thoughts is that input ranges should have two changes: 1. A different API from forward ranges 2. Be a reference type (AKA class instead of struct) In short, I disagree with your basic premise of treating the two ranges similarly. I don't want to treat them similarly, but we should be able to treat forward ranges as input ranges. Otherwise, all algorithms that work for input ranges would have to be written twice. Andrei
Re: the last change for ranges
Andrei Alexandrescu Wrote: Jason House wrote: I feel like there are too many differences between input and forward ranges for such a minor difference. Many range functions are written assuming no side effects on the caller. This can restrict the use of helper functions. It may be best to make their usage different... So how do you think we should go about it? Also don't forget that any ranges should be seamlessly and efficiently treated as input ranges. Andrei You won't like my answer! Like you've already said, the semantics of forward ranges and input ranges are different. I would argue that forward ranges have value semantics but input ranges do not. Any function that implicitly assumes value semantics is wrong. Sadly, overlapping API's makes that all too easy for someone to write bad code that passes simplistic tests with forward ranges and then fail with input ranges. My initial thoughts is that input ranges should have two changes: 1. A different API from forward ranges 2. Be a reference type (AKA class instead of struct) In short, I disagree with your basic premise of treating the two ranges similarly.
Re: the last change for ranges
== Quote from Jason House (jason.james.ho...@gmail.com)'s article Andrei Alexandrescu Wrote: Jason House wrote: I feel like there are too many differences between input and forward ranges for such a minor difference. Many range functions are written assuming no side effects on the caller. This can restrict the use of helper functions. It may be best to make their usage different... So how do you think we should go about it? Also don't forget that any ranges should be seamlessly and efficiently treated as input ranges. Andrei You won't like my answer! Like you've already said, the semantics of forward ranges and input ranges are different. I would argue that forward ranges have value semantics but input ranges do not. Any function that implicitly assumes value semantics is wrong. Sadly, overlapping API's makes that all too easy for someone to write bad code that passes simplistic tests with forward ranges and then fail with input ranges. My initial thoughts is that input ranges should have two changes: 1. A different API from forward ranges 2. Be a reference type (AKA class instead of struct) In short, I disagree with your basic premise of treating the two ranges similarly. Then how would you handle functions that only require lowest common denominator functionality? This is true for *a lot* of cases, including some important ones like finding the mean and standard deviation some object. (Incidentally, this is also where iterable comes in, since such a function doesn't even need to care if the iteration is with ranges, opApply, or the fairy #$()@* god mother, as long as foreach somehow works.) You mean to tell me you'd require explicit handling of both the input range and forward range case separately in these cases? The day this happens, I switch to Java because D will have become just as much of an insanely verbose bondage and discipline language, but with less libraries.
Re: the last change for ranges
On Wed, 20 May 2009 20:19:30 +0400, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: In wake of a few discussion I've witnessed, I'm thinking of a last change for ranges. (In fact there's one more, but that's minor.) The problem is that input ranges and forward ranges have the same syntactic interface, but different semantic interfaces. Consider the problem of finding the first two identical adjacent items in a range: R adjacentFind(R)(R r) { if (r,empty) return r; R last = r; r.popFront; for (; !r.empty last.front != r.front; last.popFront, r.popFront) { } return r; } This will work properly on lists and vectors, but horrendously on files and sockets. This is because input ranges can't be saved for later use: incrementing r also increments popFront and essentially forces both to look at the same current value. I'm thinking a better design is to require any range that's forward or better to define a function save(). Ranges that don't implement it are input ranges; those that do, will guarantee a brand new range is returned from save(). So then adjacentFind would look like this: R adjacentFind(R)(R r) { if (r,empty) return r; R last = r.save; r.popFront; for (; !r.empty last.front != r.front; last.popFront, r.popFront) { } return r; } Obviously, when you pass a range that doesn't support save, adjacentFind will not compile, which is what we want. Andrei P.S. There is a way to implement adjacentFind for forward ranges by saving data instead of ranges. I've used a limited version above for illustration purposes. Why not r.dup?
Re: the last change for ranges
On Wed, May 20, 2009 at 11:44 AM, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: Jason House wrote: Andrei Alexandrescu Wrote: Jason House wrote: I feel like there are too many differences between input and forward ranges for such a minor difference. Many range functions are written assuming no side effects on the caller. This can restrict the use of helper functions. It may be best to make their usage different... So how do you think we should go about it? Also don't forget that any ranges should be seamlessly and efficiently treated as input ranges. Andrei You won't like my answer! Like you've already said, the semantics of forward ranges and input ranges are different. I would argue that forward ranges have value semantics but input ranges do not. Any function that implicitly assumes value semantics is wrong. Sadly, overlapping API's makes that all too easy for someone to write bad code that passes simplistic tests with forward ranges and then fail with input ranges. My initial thoughts is that input ranges should have two changes: 1. A different API from forward ranges 2. Be a reference type (AKA class instead of struct) In short, I disagree with your basic premise of treating the two ranges similarly. I don't want to treat them similarly, but we should be able to treat forward ranges as input ranges. Otherwise, all algorithms that work for input ranges would have to be written twice. auto inp = std.typecons.inputRangeFromForwardRange(fwd); No need to write the algos twice now, but you do have to add a line or two of code to every input range algo. Or force the the user to call the converter function. --bb
Re: the last change for ranges
On Wed, 20 May 2009 13:04:42 -0400, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: Bill Baxter wrote: On Wed, May 20, 2009 at 9:19 AM, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: I'm thinking a better design is to require any range that's forward or better to define a function save(). Ranges that don't implement it are input ranges; those that do, will guarantee a brand new range is returned from save(). So then adjacentFind would look like this: R adjacentFind(R)(R r) { if (r,empty) return r; R last = r.save; r.popFront; for (; !r.empty last.front != r.front; last.popFront, r.popFront) { } return r; } Obviously, when you pass a range that doesn't support save, adjacentFind will not compile, which is what we want. The only other alternative that comes to mind would be forcing input ranges to hide their copy constructor, or whatever the D equivalent is, making R last = r; fail. But that would make input ranges very difficult to use. Exactly. I thought of that design, and it was difficult to even pass a range to a function. So, of those two options at least, requiring a .save sounds like the better choice. The down side is you will get no error if you write the code the first way, without a .save. I see this as turning into tip #5 in Effective D -- Know when to use .save It would be nice if that potential mistake could be eliminated somehow. You could perhaps require input ranges to implement transfer semantics, and have them implement a .clone for cases when you really do want to make an aliasing copy. Good point. I don't have a solution for that. Giving ranges move semantics would probably make for another Effective D tip (or perhaps more... move semantics are pretty brutal). Another partial solution is to define a different interface for input ranges, one that combines front() and popFront(). Something like popNext. That way, people who use only the primitives empty() and popNext() know they are using a forward range and with hope they'll remember they can't really save copies of it and expect them to remember where they are in the input. Andrei Bicycle shed: Well, since output ranges use 'put', how about 'get' for input ranges?
Re: the last change for ranges
On Wed, May 20, 2009 at 9:19 AM, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: I'm thinking a better design is to require any range that's forward or better to define a function save(). Ranges that don't implement it are input ranges; those that do, will guarantee a brand new range is returned from save(). So then adjacentFind would look like this: R adjacentFind(R)(R r) { if (r,empty) return r; R last = r.save; r.popFront; for (; !r.empty last.front != r.front; last.popFront, r.popFront) { } return r; } Obviously, when you pass a range that doesn't support save, adjacentFind will not compile, which is what we want. The only other alternative that comes to mind would be forcing input ranges to hide their copy constructor, or whatever the D equivalent is, making R last = r; fail. But that would make input ranges very difficult to use. So, of those two options at least, requiring a .save sounds like the better choice. The down side is you will get no error if you write the code the first way, without a .save. I see this as turning into tip #5 in Effective D -- Know when to use .save It would be nice if that potential mistake could be eliminated somehow. You could perhaps require input ranges to implement transfer semantics, and have them implement a .clone for cases when you really do want to make an aliasing copy. --bb
Re: the last change for ranges
== Quote from Bill Baxter (wbax...@gmail.com)'s article On Wed, May 20, 2009 at 11:44 AM, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: Jason House wrote: Andrei Alexandrescu Wrote: Jason House wrote: I feel like there are too many differences between input and forward ranges for such a minor difference. Many range functions are written assuming no side effects on the caller. This can restrict the use of helper functions. It may be best to make their usage different... So how do you think we should go about it? Also don't forget that any ranges should be seamlessly and efficiently treated as input ranges. Andrei You won't like my answer! Like you've already said, the semantics of forward ranges and input ranges are different. I would argue that forward ranges have value semantics but input ranges do not. Any function that implicitly assumes value semantics is wrong. Sadly, overlapping API's makes that all too easy for someone to write bad code that passes simplistic tests with forward ranges and then fail with input ranges. My initial thoughts is that input ranges should have two changes: 1. A different API from forward ranges 2. Be a reference type (AKA class instead of struct) In short, I disagree with your basic premise of treating the two ranges similarly. I don't want to treat them similarly, but we should be able to treat forward ranges as input ranges. Otherwise, all algorithms that work for input ranges would have to be written twice. auto inp = std.typecons.inputRangeFromForwardRange(fwd); No need to write the algos twice now, but you do have to add a line or two of code to every input range algo. Or force the the user to call the converter function. --bb But if you make the input range a class as Jason proposed, then: 1. Unless it's final, its methods will be virtual (slow). 2. You trigger a heap allocation every time you want to make this conversion. (slow)
Re: the last change for ranges
== Quote from Bill Baxter (wbax...@gmail.com)'s article On Wed, May 20, 2009 at 11:44 AM, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: Jason House wrote: Andrei Alexandrescu Wrote: Jason House wrote: I feel like there are too many differences between input and forward ranges for such a minor difference. Many range functions are written assuming no side effects on the caller. This can restrict the use of helper functions. It may be best to make their usage different... So how do you think we should go about it? Also don't forget that any ranges should be seamlessly and efficiently treated as input ranges. Andrei You won't like my answer! Like you've already said, the semantics of forward ranges and input ranges are different. I would argue that forward ranges have value semantics but input ranges do not. Any function that implicitly assumes value semantics is wrong. Sadly, overlapping API's makes that all too easy for someone to write bad code that passes simplistic tests with forward ranges and then fail with input ranges. My initial thoughts is that input ranges should have two changes: 1. A different API from forward ranges 2. Be a reference type (AKA class instead of struct) In short, I disagree with your basic premise of treating the two ranges similarly. I don't want to treat them similarly, but we should be able to treat forward ranges as input ranges. Otherwise, all algorithms that work for input ranges would have to be written twice. auto inp = std.typecons.inputRangeFromForwardRange(fwd); No need to write the algos twice now, but you do have to add a line or two of code to every input range algo. Or force the the user to call the converter function. --bb On a broader note, I think that people need to understand that, just as a free society can never be a perfectly safe society, a language that allows programmers the freedom to create concise, general and efficient constructs can never be a perfectly safe language. Yes, we could make D as safe as Java, but then programming in D would be like programming in Java--an exercise in superfluous verbosity and getting around the language's rigidity.
Re: the last change for ranges
Jason House wrote: I feel like there are too many differences between input and forward ranges for such a minor difference. Many range functions are written assuming no side effects on the caller. This can restrict the use of helper functions. It may be best to make their usage different... So how do you think we should go about it? Also don't forget that any ranges should be seamlessly and efficiently treated as input ranges. Andrei
Re: OT: on IDEs and code writing on steroids
Christopher Wright dhase...@gmail.com wrote in message news:gv0p4e$uv...@digitalmars.com... Nick Sabalausky wrote: I can see certain potential benefits to the general way C# does generics, but until the old (and I do mean old) issue of There's an IComparable, so why the hell won't MS give us an IArithmetic so we can actually use arithmetic operators on generic code? gets fixed (and at this point I'm convinced they've never had any intent of ever fixing that), I don't care how valid the reasoning behind C#'s general approach to generics is, the actual state of C#'s generics still falls squarely into the categories of crap and almost useless. IArithmetic is impossible in C# because operator overloads are static methods, and interfaces cannot specify static methods. Then how does IComparable work?
Re: the last change for ranges
On Wed, 20 May 2009 14:02:02 -0400, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: Robert Jacques wrote: Bicycle shed: Well, since output ranges use 'put', how about 'get' for input ranges? Nice color :o). In fact, put is a poor choice because it doesn't reflect advancement. Probably putNext and getNext are better. Andrei Well, on that note, more shed colors and common use cases: stacks, queues, messge passing, file I/O, network I/O, confusion factor send/recv weak , okay , good , weak ,good,low sink/rise bad , bad , bad , bad,bad ,high push/pop good , okay , okay , okay ,okay,high
Re: the last change for ranges
dsimcha wrote: == Quote from Denis Koroskin (2kor...@gmail.com)'s article Why not r.dup? .dup is supposed to imply copying of the range's contents, not copying of the range's iteration state. Yes, for arrays save() is: T[] save(T)(T[] r) { return r; } Andrei
Re: OT: on IDEs and code writing on steroids
BCS wrote: minor point; I said you have to give the compiler all the source files. You might not actually nned to compile them all, but without some external meta data, it still needs to be handled the full because it can't find them on it's own. And at that point you might as well compile them anyway. you are only considering small hobby projects. that's not true for big projects where you do not want to build all at once. Think of DWT for instance. besides, you do NOT need to provide all sources, not even just for partially processing them to find the symbols. there is no difference between C#'s /r someAssembly and GCC's -llib I don't think you fully understand the C# compilation model - in C# you almost never compile each source file separately, rather you compile a bunch of sources into an assembly all at once and you provide the list of other assemblies your code depends on. so the dependency is on the package level rather than on the file level. this make so much more sense since each assembly is a self contained unit of functionality. sure, you don't get the full power of an IDE that can track all the source files in the project for you. That just means that it's worth the money you pay for it. you can write makefiles or what ever (scons, rake, ant, ...) in the same way you'd do for C and C++. In other words: if you prefer commnad line tools you get the same experience and if you do use an IDE you get a *much* better experience. same goes for D - either write your own makefile or use rebuild which uses the compiler front-end to parse the source files just like you suggested above for C#. where did I suggest that? I replied to both you and Daniel. I think I was referring to what Daniel said here. where in all of that, do you see any contradiction to what I said? again, I said the D compilation model is ancient legacy and should be replaced and that has nothing to do with the format you prefer for your build scripts. I think that you think I'm saying something other than what I'm trying to say. I'm struggling to make my argument clear but can't seem to put it in words. My thesis is that, in effect, C# is married to VS and that D is married only to the compiler. I understand your thesis and disagree with it. what i'm saying is that not only C# is NOT married to VS but also that VS isn't even the best IDE for C#. VS is just a fancy text-editor with lots of bells and whistles. if you want a real IDE for C# you'd probably use Re-Sharper or a similar offering. My argument is that a D project can be done as nothing but a collection of .d files with no extra project files of any kind. In c# this is theoretically possible, but from any practical standpoint it's not going to be done. There is going to be some extra files that list, in some form, extra information the compiler needs to resolve symbols and figure out where to look for stuff. In any practical environment this extra bit that c# more or less forces you to have (and the D doesn't) will be maintain by some sort of IDE. this is wrong. you cannot have a big project based solely on .d files. look at DWT as an example. no matter what tool you use, let's say DSSS, it still has a config file of some sort which contains that additional meta-data. a DSSS config file might be shorter than what's required for a C# project file but don't forget that this comes from DSSS relying on rebuild which embeds the entire DMDFE. in practice, both languages need more than just the compiler. To put it quantitatively: productivity on a scale of 0 to whatever c# w/o IDE - ~1 D w/o IDE - 10 c# w/ IDE - 100+ D w/ IDE - 100+ Either C# or D will be lots more productive with an IDE but D without an IDE will be lots more productive than C# without an IDE. D is designed to be used however you want, IDE or not. C# is *designed* to be used from within VS. I rather suspect that the usability of C# without VS is very low on MS things we care about list.
Re: the last change for ranges
On Wed, May 20, 2009 at 12:05 PM, dsimcha dsim...@yahoo.com wrote: == Quote from Bill Baxter (wbax...@gmail.com)'s article On Wed, May 20, 2009 at 11:44 AM, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: Jason House wrote: Andrei Alexandrescu Wrote: Jason House wrote: I feel like there are too many differences between input and forward ranges for such a minor difference. Many range functions are written assuming no side effects on the caller. This can restrict the use of helper functions. It may be best to make their usage different... So how do you think we should go about it? Also don't forget that any ranges should be seamlessly and efficiently treated as input ranges. Andrei You won't like my answer! Like you've already said, the semantics of forward ranges and input ranges are different. I would argue that forward ranges have value semantics but input ranges do not. Any function that implicitly assumes value semantics is wrong. Sadly, overlapping API's makes that all too easy for someone to write bad code that passes simplistic tests with forward ranges and then fail with input ranges. My initial thoughts is that input ranges should have two changes: 1. A different API from forward ranges 2. Be a reference type (AKA class instead of struct) In short, I disagree with your basic premise of treating the two ranges similarly. I don't want to treat them similarly, but we should be able to treat forward ranges as input ranges. Otherwise, all algorithms that work for input ranges would have to be written twice. auto inp = std.typecons.inputRangeFromForwardRange(fwd); No need to write the algos twice now, but you do have to add a line or two of code to every input range algo. Or force the the user to call the converter function. --bb But if you make the input range a class as Jason proposed, then: 1. Unless it's final, its methods will be virtual (slow). 2. You trigger a heap allocation every time you want to make this conversion. (slow) Maybe, but I don't really agree that input ranges should be forced to be classes. Seems like they should be allowed to be either as long as they support the required methods. Actually that's a good argument for not making a = b part of the Forward Range concept. If you get rid of that one, then Forward Ranges can be either classes or structs too. --bb
Re: OT: on IDEs and code writing on steroids
Andrei Alexandrescu wrote: Lutger wrote: Andrei Alexandrescu wrote: ... What the heck do you need generics for when you have real templates? To me, generics seem like just a lame excuse for templates. I agree. Then, templates aren't easy to implement and they were understandably already busy implementing the using statement. Andrei While I don't fully understand how generics work under the hood in .NET, there are some benefits to how it is done. For example, you can use runtime reflection on generic types. And the jit compiler instantiates them at runtime. They may serve a different purpose than templates: Anders Hejlsberg: To me the best way to understand the distinction between C# generics and C++ templates is this: C# generics are really just like classes, except they have a type parameter. C++ templates are really just like macros, except they look like classes. It seems that lack of structural typing is seen as a feature: When you think about it, constraints are a pattern matching mechanism. You want to be able to say, This type parameter must have a constructor that takes two arguments, implement operator+, have this static method, has these two instance methods, etc. The question is, how complicated do you want this pattern matching mechanism to be? There's a whole continuum from nothing to grand pattern matching. We think it's too little to say nothing, and the grand pattern matching becomes very complicated, so we're in- between. From: http://www.artima.com/intv/genericsP.html Oh, so Wal^H^H^Ha friend of mine I was talking to was right: there's some missing of the point point going on. The code generation aspect of templates is a blind spot of the size of Canada. Andrei I think you miss the point here. Generics and code generation are two separate and orthogonal features that where conflated together by C++. while you can do powerful stuff with templates it smells of trying to write Haskel code with the C pre-proceesor. if you want to see a clean solution to this issue look at Nemerle. essentially, their AST Macro system provides multi-level compilation. c++ templates are a horrible hack designed to ween off C programmers from using the pre-processor and the D templates provide mostly cosmetic changes to this. they do not solve the bigger design issue.
Re: OT: on IDEs and code writing on steroids
Yigal Chripun wrote: I think you miss the point here. Generics and code generation are two separate and orthogonal features that where conflated together by C++. It's kind of odd, then, that for example the Generative Programming book (http://www.generative-programming.org) chose to treat the two notions in conjunction. while you can do powerful stuff with templates it smells of trying to write Haskel code with the C pre-proceesor. if you want to see a clean solution to this issue look at Nemerle. essentially, their AST Macro system provides multi-level compilation. c++ templates are a horrible hack designed to ween off C programmers from using the pre-processor and the D templates provide mostly cosmetic changes to this. they do not solve the bigger design issue. What is the bigger design issue? Andrei
Re: OT: on IDEs and code writing on steroids
== Quote from Yigal Chripun (yigal...@gmail.com)'s article Andrei Alexandrescu wrote: Lutger wrote: Andrei Alexandrescu wrote: ... What the heck do you need generics for when you have real templates? To me, generics seem like just a lame excuse for templates. I agree. Then, templates aren't easy to implement and they were understandably already busy implementing the using statement. Andrei While I don't fully understand how generics work under the hood in .NET, there are some benefits to how it is done. For example, you can use runtime reflection on generic types. And the jit compiler instantiates them at runtime. They may serve a different purpose than templates: Anders Hejlsberg: To me the best way to understand the distinction between C# generics and C++ templates is this: C# generics are really just like classes, except they have a type parameter. C++ templates are really just like macros, except they look like classes. It seems that lack of structural typing is seen as a feature: When you think about it, constraints are a pattern matching mechanism. You want to be able to say, This type parameter must have a constructor that takes two arguments, implement operator+, have this static method, has these two instance methods, etc. The question is, how complicated do you want this pattern matching mechanism to be? There's a whole continuum from nothing to grand pattern matching. We think it's too little to say nothing, and the grand pattern matching becomes very complicated, so we're in- between. From: http://www.artima.com/intv/genericsP.html Oh, so Wal^H^H^Ha friend of mine I was talking to was right: there's some missing of the point point going on. The code generation aspect of templates is a blind spot of the size of Canada. Andrei I think you miss the point here. Generics and code generation are two separate and orthogonal features that where conflated together by C++. while you can do powerful stuff with templates it smells of trying to write Haskel code with the C pre-proceesor. if you want to see a clean solution to this issue look at Nemerle. essentially, their AST Macro system provides multi-level compilation. c++ templates are a horrible hack designed to ween off C programmers from using the pre-processor and the D templates provide mostly cosmetic changes to this. they do not solve the bigger design issue. Not sure I agree. C++ templates were probably intended to be something like generics initially and became Turing-complete almost by accident. To get Turing completeness in C++ templates requires severe abuse of features and spaghetti code writing. D extends templates so that they're actually *designed* for metaprogramming, not just an implementation of generics, thus solving C++'s design problem. Mixins (to really allow code generation), CTFE (to make it easier to generate code), static if (to avoid kludges like using specialization just to get branching) and tuples (to handle variadics) make D templates useful for metaprogramming without massive kludges.
Re: the last change for ranges
On Wed, 20 May 2009 21:02:02 +0300, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: Robert Jacques wrote: Bicycle shed: Well, since output ranges use 'put', how about 'get' for input ranges? Nice color :o). In fact, put is a poor choice because it doesn't reflect advancement. Probably putNext and getNext are better. Andrei (Just thinking aloud... :) ) I have been using get() + set() and read() + write(). read() and write() advance to the next item; get() + set() do not. Actually I have implemented my iterator classes (in C++) as follows (simplified): BasicIFlow: read() toNext() isEnd() IFlow: get() read() toNext() isEnd() Iter: get() read() toNext() toPrev() isBegin() isFirst() isLast() isEnd() As seen, Iter is a two-way iterator, and the other two are one-way iterators. (And there are correponding output iterators too, of course.) There are also functions like toFirst(), toEnd(), etc (only Iter has toFirst()). And for convenience, Iter also has functions like getNext() and getPrev() that return the next/previous item without moving the iterator. So there are quite many functions, which is not necessary good ;) (although many of them have default functionality that simply calls the other core functions; for example, read() *could* be written with get() + toNext()). I know very little about Ranges (when I have time, that will change), but if I'm not mistaken, they hold and modify the beginning and end of the iterated area? That's an interesting and unique approach. :) My classes move a cursor inside the iterated area. Of course, with the Flow classes, the beginning of the area is moved together with the cursor (as the cursor cannot move backwards).
Re: OT: on IDEs and code writing on steroids
dsimcha wrote: Not sure I agree. C++ templates were probably intended to be something like generics initially and became Turing-complete almost by accident. That is factually correct. It was quite a hubbub on the C++ standardization committee when Erwin Unruh wrote a C++ program that wrote prime numbers in error messages. See http://tinyurl.com/oqk6nl Andrei
Re: OT: on IDEs and code writing on steroids
dsimcha wrote: == Quote from Ary Borenszweig (a...@esperanto.org.ar)'s article dsimcha escribió: == Quote from Christopher Wright (dhase...@gmail.com)'s article Nick Sabalausky wrote: Andrei Alexandrescu seewebsiteforem...@erdani.org wrote in message news:gus0lu$1sm...@digitalmars.com... I've repeatedly failed to figure out the coolness of C#, and would appreciate a few pointers. Or references. Or delegates :o). Outside of this group, I think most of the people considering C# really cool are people who are unaware of D and are coming to C# from Java. What's cool about C# is that it's like a less-shitty version of Java (and *had* good tools, although the newer versions of VS are almost as much of a bloated unresponsive mess as Eclipse - Which come to think of it, makes me wonder - If Java has gotten so fast as many people claim, why is Eclipse still such a sluggish POS?). Compare C# to D though and most of the coolness fades, even though there are still a handful of things I think D could still learn from C# (but there's probably more than a handful that C# could learn from D). Generics and reflection. Generics just hide a lot of casts, usually, but that's still quite useful. And autoboxing is convenient, though not appropriate for D. What the heck do you need generics for when you have real templates? To me, generics seem like just a lame excuse for templates. Yesterday doob reported a bug in Descent saying when you compile your project and it references a user library that has errors, when you click on the console to jump to the error, it doesn't work. I said to him: I never thought a user library could have errors! How did this happen to you? He replied: I found a bug in a template in Tango. That's why generics doesn't suck: if there's something wrong in them, the compiler tells you in compile-time. In D, you get the errors only when instantiating that template. Generics might not be as powerful as templates, but once you write one that compiles, you know you will always be able to instantiate it. Yes, but there are two flaws in this argument: 1. If you are only using templates like generics, you simply use a unit test to see if it compiles. If you're not doing anything fancy and it compiles for one or two types, it will probably compile for everything that you would reasonably expect it to. I used tango.text.xml.Document with wchar and dchar as the template type and in tango.text.xml.PullParser there were some functions that took char[] instead of T[] as the argument. http://www.dsource.org/projects/tango/ticket/1663 2. If you're doing something fancier, like metaprogramming, you have to just face the fact that this is non-trivial, and couldn't be done with generics anyhow. 3. As Bearophile alluded to, templates are really a clever hack to give you the flexibility of a dynamic language with the performance and compile time checking of a static language. This is done by moving the dynamism to instantiation time. Therefore, whereas in a dynamic language you pay at runtime in terms of the here be monsters, this code may not be being used as the author intended and tested it, with templates you pay at instantiation time. However, IMHO this is orders of magnitude better than not having that flexibility at all. I personally can't figure out how people accomplish anything in static languages w/o templates. It's just too inflexible.
Re: OT: on IDEs and code writing on steroids
Reply to Yigal, D templates provide mostly cosmetic changes to this. If you think D's templates are C++'s template with a few cosmetic changes than you aren't paying attention. A few cosmetic changes aren't going to allow 1.4MB of c++ header files to be anywhere near duplicated in 2000 LOC (Boost sprit vs dparse)
Re: OT: on IDEs and code writing on steroids
Reply to Yigal, BCS wrote: minor point; I said you have to give the compiler all the source files. You might not actually nned to compile them all, but without some external meta data, it still needs to be handled the full because it can't find them on it's own. And at that point you might as well compile them anyway. (BTW: that is only referring to c#) you are only considering small hobby projects. that's not true for big projects where you do not want to build all at once. Think of DWT for instance. besides, you do NOT need to provide all sources, not even just for partially processing them to find the symbols. there is no difference between C#'s /r someAssembly and GCC's -llib I don't think you fully understand the C# compilation model - in C# you almost never compile each source file separately, rather you compile a bunch of sources into an assembly all at once and you provide the list of other assemblies your code depends on. so the dependency is on the package level rather than on the file level. this make so much more sense since each assembly is a self contained unit of functionality. That is more or less what I thought it was. Also, that indicates that the design of c# assumes a build model that I think is a bad idea; the big dumb all or nothing build where a sub part of a program is either up to date, or rebuilt by recompiling everything in it. where in all of that, do you see any contradiction to what I said? again, I said the D compilation model is ancient legacy and should be replaced and that has nothing to do with the format you prefer for your build scripts. I think that you think I'm saying something other than what I'm trying to say. I'm struggling to make my argument clear but can't seem to put it in words. My thesis is that, in effect, C# is married to VS and that D is married only to the compiler. I understand your thesis and disagree with it. what i'm saying is that not only C# is NOT married to VS but also that VS isn't even the best IDE for C#. Maybe I should have said it's married to having *an IDE*, it's just VS by default and design. VS is just a fancy text-editor with lots of bells and whistles. if you want a real IDE for C# you'd probably use Re-Sharper or a similar offering. Last I heard Re-Sharper is a VS plugin, not an IDE in it's own right, and even if that has changed, it's still an IDE. Even so, my point is Any IDE vs. No IDE, so it dosn't address my point. My argument is that a D project can be done as nothing but a collection of .d files with no extra project files of any kind. In c# this is theoretically possible, but from any practical standpoint it's not going to be done. There is going to be some extra files that list, in some form, extra information the compiler needs to resolve symbols and figure out where to look for stuff. In any practical environment this extra bit that c# more or less forces you to have (and the D doesn't) will be maintain by some sort of IDE. this is wrong. you cannot have a big project based solely on .d files. look at DWT as an example. no matter what tool you use, let's say DSSS, it still has a config file of some sort which contains that additional meta-data. So DWT depends on DSSS's meta data. That's a design choice of DWT not D. What I'm asserting that that C# projects depending on meta data is a design choice of C# not the project. D project can (even if some don't) be practically designed so that they don't need that meta data where as, I will assert, C# projects, for practical purposes, can't do away with it. -- I'm fine with any build system you want to have implemented as long as a tool stack can still be built that works like the current one. That is that it can practically: - support projects that need no external meta data - produce monolithic OS native binary executables - work with the only language aware tool being the compiler I don't expect it to requiter that projects be done that way and I wouldn't take any issue if a tool stack were built that didn't fit that list. What I /would/ take issue with is the the language (okay, or DMD in particular) were altered to the point that one or more of those *couldn't* be done.
Re: the last change for ranges
dsimcha Wrote: == Quote from Bill Baxter (wbax...@gmail.com)'s article On Wed, May 20, 2009 at 11:44 AM, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: Jason House wrote: Andrei Alexandrescu Wrote: Jason House wrote: I feel like there are too many differences between input and forward ranges for such a minor difference. Many range functions are written assuming no side effects on the caller. This can restrict the use of helper functions. It may be best to make their usage different... So how do you think we should go about it? Also don't forget that any ranges should be seamlessly and efficiently treated as input ranges. Andrei You won't like my answer! Like you've already said, the semantics of forward ranges and input ranges are different. I would argue that forward ranges have value semantics but input ranges do not. Any function that implicitly assumes value semantics is wrong. Sadly, overlapping API's makes that all too easy for someone to write bad code that passes simplistic tests with forward ranges and then fail with input ranges. My initial thoughts is that input ranges should have two changes: 1. A different API from forward ranges 2. Be a reference type (AKA class instead of struct) In short, I disagree with your basic premise of treating the two ranges similarly. I don't want to treat them similarly, but we should be able to treat forward ranges as input ranges. Otherwise, all algorithms that work for input ranges would have to be written twice. auto inp = std.typecons.inputRangeFromForwardRange(fwd); No need to write the algos twice now, but you do have to add a line or two of code to every input range algo. Or force the the user to call the converter function. --bb But if you make the input range a class as Jason proposed, then: 1. Unless it's final, its methods will be virtual (slow). 2. You trigger a heap allocation every time you want to make this conversion. (slow) Scope classes avoid the heap allocations. Classes are not required for referance semantics. Specially constructed structs can also satisfy the requirement. By declaring the typical input range to be a (scope final) class, I was hoping to emphasize the fundamental difference with forward ranges. It should be trivial to write a (scope) wrapper that converts a forward range into an input range. The compiler should be able to optimize away the wrapper or at least inline the functions.
Re: OT: on IDEs and code writing on steroids
On Wed, May 20, 2009 at 1:09 PM, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: Yigal Chripun wrote: I think you miss the point here. Generics and code generation are two separate and orthogonal features that where conflated together by C++. It's kind of odd, then, that for example the Generative Programming book (http://www.generative-programming.org) chose to treat the two notions in conjunction. Yeh, there's definitely a overlap. Orthogonal isn't quite the right word there. I'm reading a bit on C++/CLI right now, which is C++ extended to inter-operate with CLR. C++/CLI has *both* classic C++ templates and CLR generics: templatetypename T ...// all code specializations generated at compile-time (if at all) generictypename T ... // code generated at compiletime unconditionally, specialized at run-time. I'm not clear on exactly what happens at runtime in the generic case. I had been thinking it was simply that the compiler does some type checking at compile time and the VM code then just manipulates pointers to Object from there. That may be what happens in Java generics, but in CLR generics at least you can specialize on non-Object value types and that apparently does not result in everything getting boxed. So it seems like there's a little something extra going on. I think the main reason for having Generics is that they're the best anyone currently knows how to do at the IL bytecode level. Generics give you a way to define generic parameterized types that work across all the languages that target a given VM's bytecode. But that doesn't preclude any language that targets that VM from *also* implementing compile-time templates, or code generators, or AST macros at the source code level. But the problem with source-level code generation is that you then need the source code in order to use the library. I think they were trying to avoid that with C#. If you have a compiled C# assembly, then you have everything you need to use it. Period. (I think.) At any rate, a tech that requires inclusion of source code is not very interesting to Microsoft, because Microsoft doesn't generally like to let people see their source code in the first place, and they know that many of their biggest customers don't like to either. They're nervous enough about just putting de-compileable bytecode out there. --bb
Re: the last change for ranges
Andrei Alexandrescu Wrote: In wake of a few discussion I've witnessed, I'm thinking of a last change for ranges. (In fact there's one more, but that's minor.) The problem is that input ranges and forward ranges have the same syntactic interface, but different semantic interfaces. Consider the problem of finding the first two identical adjacent items in a range: R adjacentFind(R)(R r) { if (r.empty) return r; R last = r; r.popFront; for (; !r.empty last.front != r.front; last.popFront, r.popFront) { } return r; } This will work properly on lists and vectors, but horrendously on files and sockets. This is because input ranges can't be saved for later use: incrementing r also increments popFront and essentially forces both to look at the same current value. I think that if R last = r; then after r.popFront; the order of elements in last should not change, no matter what type of range you are dealing with. (That means that input operations would be buffered to the leftmost range that still extsts.) If I understood the logic of ranges, popFront() just changes the range, and not the elements it points to.
Re: the last change for ranges
On Wed, 20 May 2009 13:35:14 -0400, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: Jason House wrote: I feel like there are too many differences between input and forward ranges for such a minor difference. Many range functions are written assuming no side effects on the caller. This can restrict the use of helper functions. It may be best to make their usage different... So how do you think we should go about it? Also don't forget that any ranges should be seamlessly and efficiently treated as input ranges. Andrei struct Input(R) // enforce that R is a forward range for type T, not versed well enough in D2 to know how to do this yet { R _range; // make this R * if you want Input(R) to be a reference type alias _range this; auto popNext() { auto result = _range.front; _range.popFront(); return result; } // and so-on, can leave out truly duplicate functions like empty as the alias this will take care of that. } // convenience method Input!(R) asInput(R)(R r) { return Input!(R)(r); // or Input!(R)(new R(r)); if reference type is the right answer } No extra code required in any forward range, just wrap it. Input still retains the forward range functions as an underlying base if you need BOTH input and forward range functionality (not sure why). -Steve
Re: the last change for ranges
== Quote from Jason House (jason.james.ho...@gmail.com)'s article IMHO, D should have a type with low size and function call overhead like a struct as well as reference semantics like a class. What's wrong with a pointer to a heap-allocated struct? I sometimes need what you describe, too, and I've never seen a case where this doesn't do the job.
Re: the last change for ranges
On Wed, May 20, 2009 at 4:03 PM, dsimcha dsim...@yahoo.com wrote: == Quote from Jason House (jason.james.ho...@gmail.com)'s article IMHO, D should have a type with low size and function call overhead like a struct as well as reference semantics like a class. What's wrong with a pointer to a heap-allocated struct? I sometimes need what you describe, too, and I've never seen a case where this doesn't do the job. And you can alias Foo_* Foo, so that it doesn't even look like you're passing around a pointer. :-) --bb
Re: with still sucks + removing features + adding features
Andrei Alexandrescu wrote: ... So we're looking at a number of problems here. One is that we'd need to change the language in several places to accommodate an ill-conceived feature. Another is that I can't seem to get some very simple points across such as the difference between a token and a non-terminal, in spite of having tried repeatedly and in various forms. Another is that I am becoming suffocated with self-righteousness and therefore am losing goodwill in this thread at an exponentially-increasing rate. Finally, it looks like such discussions necessitate more than a full-time job. Andrei You could ask Walter for advice on most of these matters ;)
Re: the last change for ranges
MLT wrote: I think that if R last = r; then after r.popFront; the order of elements in last should not change, no matter what type of range you are dealing with. (That means that input operations would be buffered to the leftmost range that still extsts.) If I understood the logic of ranges, popFront() just changes the range, and not the elements it points to. That's the case for all ranges except input ranges. Consider: FileByCharacter { private FILE* _f; private dchar _last; bool empty() { return _last == 0x; } void popFront() { _last = fgetc(_f); } dchar front() { return _last; } } Consider what happens when you copy this range around. Andrei
Re: the last change for ranges
dsimcha Wrote: == Quote from Jason House (jason.james.ho...@gmail.com)'s article IMHO, D should have a type with low size and function call overhead like a struct as well as reference semantics like a class. What's wrong with a pointer to a heap-allocated struct? I sometimes need what you describe, too, and I've never seen a case where this doesn't do the job. That does the job, but it looks ugly ;) I think it's also not allowed in safe d.
Re: the last change for ranges
Bill Baxter Wrote: On Wed, May 20, 2009 at 4:03 PM, dsimcha dsim...@yahoo.com wrote: == Quote from Jason House (jason.james.ho...@gmail.com)'s article IMHO, D should have a type with low size and function call overhead like a struct as well as reference semantics like a class. What's wrong with a pointer to a heap-allocated struct? I sometimes need what you describe, too, and I've never seen a case where this doesn't do the job. And you can alias Foo_* Foo, so that it doesn't even look like you're passing around a pointer. :-) --bb Interesting thought. Wouldn't calls to new still require use of Foo__?
Re: the last change for ranges
Andrei Alexandrescu Wrote: MLT wrote: I think that if R last = r; then after r.popFront; the order of elements in last should not change, no matter what type of range you are dealing with. (That means that input operations would be buffered to the leftmost range that still extsts.) If I understood the logic of ranges, popFront() just changes the range, and not the elements it points to. That's the case for all ranges except input ranges. Consider: FileByCharacter { private FILE* _f; private dchar _last; bool empty() { return _last == 0x; } void popFront() { _last = fgetc(_f); } dchar front() { return _last; } } Consider what happens when you copy this range around. Andrei You didn't declare FileByCharacter as either a struct or a class? Did I plant a seed? :)
Re: the last change for ranges
== Quote from Jason House (jason.james.ho...@gmail.com)'s article dsimcha Wrote: == Quote from Jason House (jason.james.ho...@gmail.com)'s article IMHO, D should have a type with low size and function call overhead like a struct as well as reference semantics like a class. What's wrong with a pointer to a heap-allocated struct? I sometimes need what you describe, too, and I've never seen a case where this doesn't do the job. That does the job, but it looks ugly ;) I think it's also not allowed in safe d. Well then that argues more for a generic reference type than for a whole new aggregate type different from both classes and structs. IIRC, Ref was supposed to be coming to std.typecons soon. Also, if you don't care about the few bytes of overhead for vtbl and monitor, there's always final classes. The bottom line is that I can see where what you're asking for could be useful, but the cases where neither a final class nor a pointer to a heap-allocated struct cut it are way too few and far between to justify a whole new aggregate type.
Re: the last change for ranges
On Wed, May 20, 2009 at 5:11 PM, Jason House jason.james.ho...@gmail.com wrote: Bill Baxter Wrote: On Wed, May 20, 2009 at 4:03 PM, dsimcha dsim...@yahoo.com wrote: == Quote from Jason House (jason.james.ho...@gmail.com)'s article IMHO, D should have a type with low size and function call overhead like a struct as well as reference semantics like a class. What's wrong with a pointer to a heap-allocated struct? I sometimes need what you describe, too, and I've never seen a case where this doesn't do the job. And you can alias Foo_* Foo, so that it doesn't even look like you're passing around a pointer. :-) --bb Interesting thought. Wouldn't calls to new still require use of Foo__? Yes. Also if you're creating 'em on the stack. --bb
Re: OT: on IDEs and code writing on steroids
Nick Sabalausky wrote: Christopher Wright dhase...@gmail.com wrote in message news:gv0p4e$uv...@digitalmars.com... Nick Sabalausky wrote: I can see certain potential benefits to the general way C# does generics, but until the old (and I do mean old) issue of There's an IComparable, so why the hell won't MS give us an IArithmetic so we can actually use arithmetic operators on generic code? gets fixed (and at this point I'm convinced they've never had any intent of ever fixing that), I don't care how valid the reasoning behind C#'s general approach to generics is, the actual state of C#'s generics still falls squarely into the categories of crap and almost useless. IArithmetic is impossible in C# because operator overloads are static methods, and interfaces cannot specify static methods. Then how does IComparable work? It uses a member function instead.
Re: the last change for ranges
Andrei Alexandrescu Wrote: MLT wrote: I think that if R last = r; then after r.popFront; the order of elements in last should not change, no matter what type of range you are dealing with. (That means that input operations would be buffered to the leftmost range that still extsts.) If I understood the logic of ranges, popFront() just changes the range, and not the elements it points to. That's the case for all ranges except input ranges. Consider: FileByCharacter { private FILE* _f; private dchar _last; bool empty() { return _last == 0x; } void popFront() { _last = fgetc(_f); } dchar front() { return _last; } } Consider what happens when you copy this range around. Andrei I thought more of something like: FileByCharacter { private FILE* _f; private dchar[] _buf; bool empty() { return _buf[0] == 0x; } void popFront() { _buf = _buf[1..$] ; if( _buf.length 1 ) _buf ~= fgetc(_f); } dchar front() { return _buf[0]; } } The idea is that you continue to expand an array. Another copy of the range will continue to step over the same array. This doesn't really work, because the second copy doesn't really know how much the first copy already read. But that should be fixable the problem is in the line if( _buf.length 1 ) _buf ~= fgetc(_f); which should only trigger if _buf reached the end of the read part, not the end of the current copy of _buf. I'm also not sure if D's GC will handle dropping the part of the array that no one looks at. One needs something like a lazy semi-infinite range, that only calls a certain function when it reaches an unexplored part.
Re: the last change for ranges
MLT wrote: One needs something like a lazy semi-infinite range, that only calls a certain function when it reaches an unexplored part. That's a great abstraction, but we can't afford to impose that to everybody. There must be an abstraction for a one-pass go through an arbitrarily long stream. Anyhow, I decided to change ranges as follows: a) Input: bool empty(); ref T popNext(); b) Output: void putNext(T); c) Forward: bool empty(); ref T front(); void popFront(); The function ref T popNext() is a nonmember that accepts any forward range and uses front() and popFront(). Of course, a forward range is welcome to implement popFront as a member if it so wishes. The function putNext() overwrites front() and then calls popFront. d) Bidirectional: bool empty(); ref T front(); void popFront(); ref T back(); void popBack(); popNext, putNext apply as for forward ranges. e) Random bool empty(); ref T front(); void popFront(); ref T back(); void popBack(); ref T opIndex(uint n); void opIndexAssign(T, uint n); popNext, putNext apply as for forward ranges. We need to fix the opIndexAssign mess. Andrei
Re: the last change for ranges
== Quote from Andrei Alexandrescu (seewebsiteforem...@erdani.org)'s article MLT wrote: One needs something like a lazy semi-infinite range, that only calls a certain function when it reaches an unexplored part. That's a great abstraction, but we can't afford to impose that to everybody. There must be an abstraction for a one-pass go through an arbitrarily long stream. Anyhow, I decided to change ranges as follows: a) Input: bool empty(); ref T popNext(); b) Output: void putNext(T); c) Forward: bool empty(); ref T front(); void popFront(); The function ref T popNext() is a nonmember that accepts any forward range and uses front() and popFront(). Of course, a forward range is welcome to implement popFront as a member if it so wishes. The function putNext() overwrites front() and then calls popFront. d) Bidirectional: bool empty(); ref T front(); void popFront(); ref T back(); void popBack(); popNext, putNext apply as for forward ranges. e) Random bool empty(); ref T front(); void popFront(); ref T back(); void popBack(); ref T opIndex(uint n); void opIndexAssign(T, uint n); popNext, putNext apply as for forward ranges. We need to fix the opIndexAssign mess. Andrei Please, please, please PLEASE, PRETTY PLEASE FOR THE LOVE OF GOD ALMIGHTY tell me you're not serious!!! Isn't changing the interface such that forward ranges are no longer effectively a subtype of input ranges a bit drastic? Or do you have some magic up your sleeve that, given any forward range, will automatically call popFront, and then front, when popNext is called, using extension function hacks or something? The whole beauty of ranges is that they provide one standard interface to program to if all you need is a lowest common denominator level of functionality. Frankly, if you destroy this, I think that just enforcing forward vs. input ranges purely by convention would be the lesser of two evils.
Re: the last change for ranges
== Quote from Andrei Alexandrescu (seewebsiteforem...@erdani.org)'s article MLT wrote: One needs something like a lazy semi-infinite range, that only calls a certain function when it reaches an unexplored part. That's a great abstraction, but we can't afford to impose that to everybody. There must be an abstraction for a one-pass go through an arbitrarily long stream. Anyhow, I decided to change ranges as follows: a) Input: bool empty(); ref T popNext(); b) Output: void putNext(T); c) Forward: bool empty(); ref T front(); void popFront(); The function ref T popNext() is a nonmember that accepts any forward range and uses front() and popFront(). Of course, a forward range is welcome to implement popFront as a member if it so wishes. The function putNext() overwrites front() and then calls popFront. d) Bidirectional: bool empty(); ref T front(); void popFront(); ref T back(); void popBack(); popNext, putNext apply as for forward ranges. e) Random bool empty(); ref T front(); void popFront(); ref T back(); void popBack(); ref T opIndex(uint n); void opIndexAssign(T, uint n); popNext, putNext apply as for forward ranges. We need to fix the opIndexAssign mess. Andrei (Bangs head against desk.) Sorry. Didn't see the part about the non-member popNext(), though this would require Walter to make extension methods work for structs, which should probably happen anyway.
Re: the last change for ranges
dsimcha wrote: Please, please, please PLEASE, PRETTY PLEASE FOR THE LOVE OF GOD ALMIGHTY tell me you're not serious!!! Isn't changing the interface such that forward ranges are no longer effectively a subtype of input ranges a bit drastic? Or do you have some magic up your sleeve that, given any forward range, will automatically call popFront, and then front, when popNext is called, using extension function hacks or something? Consider: struct R { bool empty(); ref int front(); void popFront(); } ref int popNext(ref R fwdRange) { auto result = fwdRange.front(); fwdRange.popFront; return *result; } void main() { R r; int x = r.popNext; } This should work, I just noticed with surprise it doesn't. It's a bug, specifically bug 3015: http://d.puremagic.com/issues/show_bug.cgi?id=3015 The whole beauty of ranges is that they provide one standard interface to program to if all you need is a lowest common denominator level of functionality. Frankly, if you destroy this, I think that just enforcing forward vs. input ranges purely by convention would be the lesser of two evils. You and I see eye to eye. Andrei
Re: the last change for ranges
dsimcha wrote: == Quote from Andrei Alexandrescu (seewebsiteforem...@erdani.org)'s article MLT wrote: One needs something like a lazy semi-infinite range, that only calls a certain function when it reaches an unexplored part. That's a great abstraction, but we can't afford to impose that to everybody. There must be an abstraction for a one-pass go through an arbitrarily long stream. Anyhow, I decided to change ranges as follows: a) Input: bool empty(); ref T popNext(); b) Output: void putNext(T); c) Forward: bool empty(); ref T front(); void popFront(); The function ref T popNext() is a nonmember that accepts any forward range and uses front() and popFront(). Of course, a forward range is welcome to implement popFront as a member if it so wishes. The function putNext() overwrites front() and then calls popFront. d) Bidirectional: bool empty(); ref T front(); void popFront(); ref T back(); void popBack(); popNext, putNext apply as for forward ranges. e) Random bool empty(); ref T front(); void popFront(); ref T back(); void popBack(); ref T opIndex(uint n); void opIndexAssign(T, uint n); popNext, putNext apply as for forward ranges. We need to fix the opIndexAssign mess. Andrei (Bangs head against desk.) Sorry. Didn't see the part about the non-member popNext(), though this would require Walter to make extension methods work for structs, which should probably happen anyway. I should learn to never post before reading all messages... Andrei
Re: OT: on IDEs and code writing on steroids
Christopher Wright dhase...@gmail.com wrote in message news:gv29vn$7a...@digitalmars.com... Nick Sabalausky wrote: Christopher Wright dhase...@gmail.com wrote in message news:gv0p4e$uv...@digitalmars.com... Nick Sabalausky wrote: I can see certain potential benefits to the general way C# does generics, but until the old (and I do mean old) issue of There's an IComparable, so why the hell won't MS give us an IArithmetic so we can actually use arithmetic operators on generic code? gets fixed (and at this point I'm convinced they've never had any intent of ever fixing that), I don't care how valid the reasoning behind C#'s general approach to generics is, the actual state of C#'s generics still falls squarely into the categories of crap and almost useless. IArithmetic is impossible in C# because operator overloads are static methods, and interfaces cannot specify static methods. Then how does IComparable work? It uses a member function instead. And they can't do the same for arithmetic?
Re: OT: on IDEs and code writing on steroids
Bill Baxter wbax...@gmail.com wrote in message news:mailman.151.1242855932.13405.digitalmar...@puremagic.com... On Wed, May 20, 2009 at 1:09 PM, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: Yigal Chripun wrote: I think you miss the point here. Generics and code generation are two separate and orthogonal features that where conflated together by C++. It's kind of odd, then, that for example the Generative Programming book (http://www.generative-programming.org) chose to treat the two notions in conjunction. Yeh, there's definitely a overlap. Orthogonal isn't quite the right word there. I'm reading a bit on C++/CLI right now, which is C++ extended to inter-operate with CLR. C++/CLI has *both* classic C++ templates and CLR generics: templatetypename T ...// all code specializations generated at compile-time (if at all) generictypename T ... // code generated at compiletime unconditionally, specialized at run-time. I'm not clear on exactly what happens at runtime in the generic case. I had been thinking it was simply that the compiler does some type checking at compile time and the VM code then just manipulates pointers to Object from there. That may be what happens in Java generics, but in CLR generics at least you can specialize on non-Object value types and that apparently does not result in everything getting boxed. So it seems like there's a little something extra going on. I think the main reason for having Generics is that they're the best anyone currently knows how to do at the IL bytecode level. Generics give you a way to define generic parameterized types that work across all the languages that target a given VM's bytecode. But that doesn't preclude any language that targets that VM from *also* implementing compile-time templates, or code generators, or AST macros at the source code level. But the problem with source-level code generation is that you then need the source code in order to use the library. I think they were trying to avoid that with C#. If you have a compiled C# assembly, then you have everything you need to use it. Period. (I think.) At any rate, a tech that requires inclusion of source code is not very interesting to Microsoft, because Microsoft doesn't generally like to let people see their source code in the first place, and they know that many of their biggest customers don't like to either. They're nervous enough about just putting de-compileable bytecode out there. Maybe this is naive, but what about an AST-level template/generic? Couldn't that provide for the best of both worlds? For instance, suppose (purely hypothetically) that the .NET assembly system were changed to allow the source for a D/C++ style of source-level template to be embedded into the assembly. Then they'd be able to do D/C++ style source-level template/code-generation. Right? Now obviously the big problem with that is it would only be usable in the same language it was originally written in. So, instead of getting that cross-language support by going all the way down to the IL bytecode level to implement generics (which, as you said, would somehow prevent the flexibility that the D/C++ style enjoys) suppose it only went down as far as a language-agnostic AST? I suppose that might make reverse-engineering easier which MS might not like, but I'm not suggesting this as something that MS should like or should even do, but rather suggesting it as (business issues completely aside) something that would possibly gain the benefits of both styles.
Re: the last change for ranges
Andrei Alexandrescu seewebsiteforem...@erdani.org wrote in message news:gv2hj8$k1...@digitalmars.com... dsimcha wrote: Consider: struct R { bool empty(); ref int front(); void popFront(); } ref int popNext(ref R fwdRange) { auto result = fwdRange.front(); fwdRange.popFront; return *result; } void main() { R r; int x = r.popNext; } This should work, I just noticed with surprise it doesn't. It's a bug, specifically bug 3015: http://d.puremagic.com/issues/show_bug.cgi?id=3015 I thought that was only supposed to work for arrays. Has that changed? If so, what's the new rule?
Re: OT: on IDEs and code writing on steroids
Nick Sabalausky wrote: ... Maybe this is naive, but what about an AST-level template/generic? Couldn't that provide for the best of both worlds? For instance, suppose (purely hypothetically) that the .NET assembly system were changed to allow the source for a D/C++ style of source-level template to be embedded into the assembly. Then they'd be able to do D/C++ style source-level template/code-generation. Right? Now obviously the big problem with that is it would only be usable in the same language it was originally written in. So, instead of getting that cross-language support by going all the way down to the IL bytecode level to implement generics (which, as you said, would somehow prevent the flexibility that the D/C++ style enjoys) suppose it only went down as far as a language-agnostic AST? ... What I've always thought might be an interesting experiment would be to change templates in LDC so that instead of generating an AST, they generate code that generates code. So when you use A!(T), what happens is that at runtime the template is run with T as an argument. This generates a chunk of LLVM bitcode which LLVM then assembles to machine code and links into the program. This alleviates the problem with using source in that if you embed the template's actual source, then you suddenly ALSO have to embed the standard library's source and the source of any other libraries you happened to compile with. Oh, and the same version of the compiler. -- Daniel
Re: the last change for ranges
Andrei Alexandrescu wrote: struct R { bool empty(); ref int front(); void popFront(); } ref int popNext(ref R fwdRange) { auto result = fwdRange.front(); fwdRange.popFront; return *result; } void main() { R r; int x = r.popNext; } This should work, I just noticed with surprise it doesn't. It's a bug, specifically bug 3015: http://d.puremagic.com/issues/show_bug.cgi?id=3015 Yes. Oh yes. YES!!!