Re: this is almost a workaround for the lack of named parameters
On Saturday, 23 March 2013 at 15:00:13 UTC, bearophile wrote: foobar: Code that needs named parameters to be more readable is poorly designed code in the first place. Have you used a language where the usage of named arguments is idiomatic, like Python, Scala or Ada? They are sometimes useful even for well designed code, like functions with two arguments. Bye, bearophile idiomatic is a relative term, tightly coupled to a specific language. Idiomatic D code for example is very different from idiomatic Haskell code. Idiomatic Python style in D would be very unidiomatic D code and vise versa. Each language has its own conventions, styles, set of distinct features, etc, etc and trying to use language A style while coding in language B is like trying to fit a square peg in a round hole. For instance, I would NOT use smalltalk naming conventions while writing say Java code. Both have very good and very consistent styles that are tightly coupled with their respective syntaxes and are very unsuitable to use in the other language. In short, if you want to discuss python features, style or specific math plotting libraries, please post to the python mailing list, not D's NG.
Re: this is almost a workaround for the lack of named parameters
On Saturday, 23 March 2013 at 15:59:12 UTC, Jacob Carlborg wrote: On 2013-03-23 16:55, John Colvin wrote: A simple example is matplotlib.pyplot.plot There are so many possible flags and parameters that can be passed in order to get the exact behaviour you want, but commonly you'll only want a few set for each call. You don't want to have to set all the other preceding parameters, you just want to go e.g. plot(data, linewidth=5) I've heard it was a big boost for C# when it got support for default arguments and named parameters. It made it a lot easier to integrate with COM. AFAIK, this is only relevant or useful for COM (i.e. to support legacy, not really OO code) and is not supported (compile error?) for regular C# code as it is *not idiomatic C#* style (and is not OO).
Re: this is almost a workaround for the lack of named parameters
On Monday, 25 March 2013 at 13:02:49 UTC, bearophile wrote: foobar: idiomatic is a relative term, tightly coupled to a specific language. Idiomatic D code for example is very different from idiomatic Haskell code. Idiomatic Python style in D would be very unidiomatic D code and vise versa. Each language has its own conventions, styles, set of distinct features, etc, etc and trying to use language A style while coding in language B is like trying to fit a square peg in a round hole. For instance, I would NOT use smalltalk naming conventions while writing say Java code. Both have very good and very consistent styles that are tightly coupled with their respective syntaxes and are very unsuitable to use in the other language. In short, if you want to discuss python features, style or specific math plotting libraries, please post to the python mailing list, not D's NG. Imperative/OOP languages are not totally different from each other, both Python and D derive strongly from C that comes partially from Algol, and D copies several things from Python (string functions, part of the module system, part of the range design comes from itertools, and so on). So comparing languages and their features is very useful. If you have not used named arguments in languages that idiomatically use them, then it's not easy for you to see how and why they are sometimes useful and good. In Python function arguments don't have a type, so named arguments are more useful than in D. But from my experience in Python, I believe D could enjoy named arguments. Bye, bearophile C is a HORRIBLE language regarding naming conventions and is a *very poor choice* to learn from in this regard. Python sets very high expectations regarding beautiful code and IMHO fails miserably (more so because of the starting higher expectations). I admit to being spoiled by actually beautifully designed languages that are far superior in that respect. I suggest to learn Smalltalk for a language that emphasizes code readability decades before Python became cool. I find Ruby which is based on Smalltalk's semantics and spirit to be more elegant and less pretentious compared to Python.
Re: this is almost a workaround for the lack of named parameters
On Friday, 22 March 2013 at 21:41:46 UTC, John Colvin wrote: On Friday, 22 March 2013 at 21:29:46 UTC, foobar wrote: On Friday, 22 March 2013 at 21:10:27 UTC, John Colvin wrote: On Friday, 22 March 2013 at 20:04:14 UTC, foobar wrote: WTF? What do kwargs have to do with programming? Sounds more like a half-Klingon half-Ferengi species to me. kwargs = keyword arguments It's a common naming convention in python, as exemplified in matplotlib. That was meant more as a rhetorical question rather than a real one. Yes, I guessed the meaning by the surrounding context but nevertheless it was a major WAT while skimming the post. Also, Who the fuck cares whats common in Python? I was reading and replying on the *D* NG, was I not? Kwarg seems a reasonable name, consistent with a pre-existing convention. Please suggest a better alternative if you have one. I must admit I'm bemused by your level of aggression over what appears to be a trivial matter. Your read it wrong. Not aggression but rather annoyment. Also, code readability is NOT a trivial matter and people who think that it is should have their keyboard chopped off. IMHO, I think the entire feature is a code smell and glad D does not support it. Code that needs named parameters to be more readable is poorly designed code in the first place.
Re: this is almost a workaround for the lack of named parameters
On Friday, 22 March 2013 at 10:17:02 UTC, J wrote: With credit for inspiration to David Medlock in this post-- http://forum.dlang.org/thread/d9lnrr$26q3$1...@digitaldaemon.com ... // Tongue firmly in cheek, I'd like to introduce // the NAPAPISS principle: (with apologies to SFINAE and RAII) // NAPAPISS = NAmed Parameters Are simply Passed in a Struct, Silly. // Yes, indeed, maybe this is what happens after drinking too much of // the fine wine products from the Napa valley... you start having // wild flights of fancy of how D might surprisingly soon have // named parameters import std.stdio; import std.c.stdlib; void main(string[] arg) { // this works today: but with the drawback that the // named params must be known at compile time... // Here is a named param call, // as compact as I could get it (see struct below for actual definition). auto a = myfunc!q{ z= 2; x = -123; y = 200 }(0)(); // calls opCall writeln(a=, a); // prints a=yo, as returned from opCall // And here's the runtime version, unfortunately you have to // pre-declare g because otherwise it won't survive the scope, and // the return value from myfunc.opCall would become inaccessible. string g; with(myfunc!()(0)) { x=rand() % 40; y=x/2; z=y/2; g = call(); // as a side effect, prints 'X 7, Y 3, Z 1' } writeln(g=, g); // prints g=yo, as returned from opCall /* // The bright future: this demonstrates that // it would be fairly trivial to make some kind of annotation // like @kwarg or whaterver, to indicate that a function // was using this calling convention: @kwarg string f(int a, string b) { body; } // so that @kwarg function definitions are lowered to: struct f_kw { int a; string b; string f() { body; } } // and calls to @kwarg functions are transformed // from this: auto r = f(a=5, b=good); // into this: f_kw tmp34; tmp34.a = 5; tmp34.b = good; auto r = tmp34.f(); // the benefit: named parameters can be used in a natural way, // and they need be known only at runtime. */ } // how the 'works today' above examples were implemented: struct myfunc(string init_string=) { // named keyword or named parameters // --the call arguments and their defaults int x=0; int y=0; int z=0; this(int) {} string opCall() { mixin(init_string ~ ;); writefln(X %s, Y %s, Z %s, x, y, z ); return yo; } alias opCall call; } On Friday, 22 March 2013 at 09:18:33 UTC, J wrote: The bigger point here is more profound: it is trivial to implement named parameters using structs + trivial lowerings, and this is no way conflicts with function overloading. D deserves to have named parameters to functions -- it makes for much more legible code, and obviates the need for slow builder patterns. Readable and speedable. It's win-win. WTF? What do kwargs have to do with programming? Sounds more like a half-Klingon half-Ferengi species to me.
Re: this is almost a workaround for the lack of named parameters
On Friday, 22 March 2013 at 21:10:27 UTC, John Colvin wrote: On Friday, 22 March 2013 at 20:04:14 UTC, foobar wrote: WTF? What do kwargs have to do with programming? Sounds more like a half-Klingon half-Ferengi species to me. kwargs = keyword arguments It's a common naming convention in python, as exemplified in matplotlib. That was meant more as a rhetorical question rather than a real one. Yes, I guessed the meaning by the surrounding context but nevertheless it was a major WAT while skimming the post. Also, Who the fuck cares whats common in Python? I was reading and replying on the *D* NG, was I not?
Re: Are there any default dmd optimizations
On Wednesday, 27 February 2013 at 21:57:06 UTC, Andrei Alexandrescu wrote: On 2/27/13 3:16 PM, Jacob Carlborg wrote: On 2013-02-27 14:29, Andrei Alexandrescu wrote: Four years ago I would've entirely agreed. But right now it's an odd comment to make seeing as we're discussing all major decisions in this group and we're switching full-bore to DIPs. The alias this syntax the foobar mentioned was removed under the radar and only discussed in a pull request. I agree we were sloppy on that. Kenji was feeling strong about and Walter and I didn't have particular objections, so we gave him green light. In the process we neglected backward compatibility. Andrei At a bare minimum, there should be a well defined place to notify *users* (NOT DMD contributers) about language changes *ahead of time*. If such place is not defined, than people do not know where to look for that info if that is even available at all. This at least will remove the element of surprise. For D to be really open as it claims to be, there should be additional guidelines about the decision making process itself. This should be made accessible for *users* (D programmers). I need not be a core DMD contributer, nor should I need to know C++ or DMD's internals, Nor should I need to browse among hundreds of bugs on bugzilla or pull requests on github (both can be labeled very poorly) to discern out of that sea of information what are the *few* visible changes to the language and core library APIs.
Re: Are there any default dmd optimizations
On Tuesday, 26 February 2013 at 23:37:57 UTC, Andrei Alexandrescu wrote: snip Agreed, but it does happen often that a language feature is later superseded by a generalization thereof. Andrei I agree that this does happen. The question is how the language evolve with that in mind. Do we choose to preserve *all* previous semantics? Do we have a proper deprecation process? etc, etc.. I think that unfortunately, the D design process is not adequate as of yet - there is no proper deprecation process which causes things like a sudden death for previously valid syntax (alias syntax) instead of gradually deprecate it with proper announcements *everywhere* (website, NG, ..) on the one hand and keeping redundant special cases in the language and refusing to change semantics (AAs) to allow for an easier path forward, on the other hand. So I think we agree on the spirit of things but the problems I'm voicing are about the details or lack thereof. Where are the guidelines describing all these issues? How to address required semantic changes in the language? how to address syntax changes? how to remove previously failed features or no longer needed ones? What constitutes a feature that should be completely removed and what should only be put on permanent deprecation status? How all those things interact? If we still (after a decade!) decide these based on c++ common wisdom only than I think something is really broken here. Previously valid D syntax is easily broken without much regard yet we are still stuck on the comma backwards compatibility to C. We ignore all other languages that programmers migrate from to D and ignore their common wisdom and experience. Isn't it time for D to become its own language instead of a leech on C++ idioms?
Re: Are there any default dmd optimizations
On Wednesday, 27 February 2013 at 00:01:31 UTC, Andrei Alexandrescu wrote: I understand how you see it, and honestly could see it from a mile. When a post (a) cherry-picks all negatives and (b) has a final tone that mentions no possible solution - it's a foregone conclusion that no amount of explaining, amending, arguing, etc. will improve the poster's outlook. I could say e.g. Well I think things have changed, and look we've turned the bug trend curve (http://goo.gl/kf4ZC) which is unprecedented, fixed some incomplete features, break new records on bug fixes with each release, and have a big conference coming. - to which I have no doubt it's possible to concoct a negative answer. So I understand you have a negative outlook on D. That's entirely fine, as is mentioning it on the forum. The only thing I'd like you to understand and appreciate is that we who work on D are doing our best to find solutions to the various problems in front of us, and in quite a literal sense we don't know how to do any better. The constructive thing I'm getting out of this is that we could use some more radicalization - try things that push stronger against our comfort zone. I have a few in mind but it's too early to discuss them publicly. Andrei Let me emphasize again, I did *not* intend to discuss the specific features, Walter brought that topic up. I intended to point out the lack of good general guidelines for the D design process. And i did actually mention one (partial) solution. I mean no disrespect to the hard work of the contributers and did not wish to discourage them, just to prevent wasted effort due to lack of proper guidelines. The other criticism I have is exactly the last paragraph above. Rust is designed in the open and so I can read the weekly minutes and get the bigger picture of the design process, what are the different proposed alternatives, what are the considerations and trade-offs, etc. In D on the other hand, it's all closed. D claims that it is an open source project but all the major design decisions happen personally between you and Walter and this is worse than big company languages that at least publish some articles online.
Re: Are there any default dmd optimizations
On Monday, 25 February 2013 at 22:26:33 UTC, Walter Bright wrote: On 2/25/2013 2:00 PM, foobar wrote: On Sunday, 24 February 2013 at 22:28:46 UTC, Walter Bright wrote: By baking one scheme into the language, people will rarely feel a need to reinvent the wheel, and will go on to more productive uses of their time. This is a fallacy caused by the culture of c++ programmers - there is exactly *zero* benefit in baking this into the language. On the contrary, I think it has turned out rather well. Another success story of baking certain things into the language is Ddoc. Unittest is a third. They've been big wins for D. None of those strictly has to be in the language - they can be done by convention and 3rd party tools. Nevertheless, convenience, standardization and mechanical enforcement of a convention seem to work better than applying religious zeal to enforce a convention. DDoc isn't part of the language but rather part of the compiler, nevertheless it has its downsides. Being part of the compiler means that the compiler needs to be changed to address those and it isn't even written in D! The end result is all sort of additional auxiliary D utilities to post-process this in order to address some of those issues. Hence, A prime example of the failure that I'm talking about. unittest is worse, it is indeed part of the language so now the _language grammar_ needs to be changed to fix the problems with it, such as not having test names. A far better solution practiced in all other major languages is to use annotations and in fact, there probably already are similar D frameworks, thus exhibiting the same problem of multiple conflicting implementations you wished to avoid. Additional such problems - the AA issue which has been going own for years now. The endless discussions regarding tuples. It seems that D strives to bloat the language with needless features that really should have been standardized in the library and on the other hand tries to put in the library things that really ought to be built into the language to benefit from proper integration and syntax. The latest case was the huge properties debate and its offshoots regarding ref semantics which I didn't even bother participate in. Bartosz developed an ownership system for D to address all the safety issues raised by ref *years ago* and it was rejected due to complexity. Now, Andrei tries to achieve similar safety guaranties by giving ref the semantics of borrowed pointers. It all seems to me like trying to build an airplane without wings cause they are too complex. Rust on the other hand already integrated an ownership system and is already far ahead of D's design. D had talked about macros *years ago* and rust already implemented them. All of this is to say, that instead of trying to fix the c++ culture in D, we should try to create a *better* D culture. We do have a significantly better D culture than the C++ one. For example, C++ relies heavily and unapologetically on convention for writing correct, robust code. D eschews that, and instead is very biased towards mechanical verification. I call bullshit. This is an half hearted intention at best. @safe has holes in it, integers has no overflow checks, ref also has holes, Not only D has null pointer bugs but they also cause segfaults. In fact there are many such not c++ features in D and which is why I find other languages such as rust a *much* better design and it evolves much faster because it is designed in terms of - what we want to achieve, how best to implement that. How does rust handle this particular issue?
Re: Are there any default dmd optimizations
On Tuesday, 26 February 2013 at 10:59:41 UTC, Dicebot wrote: I agree with all but small comment on unit tests : current approach makes it really easy to start adding tests for projects that do not have them and this is huge. So having unittest blocks themselves is really a success feature. Tightly coupling handling of this blocks to compiler is an issue though. Again, this is a completely superfluous feature. D already has annotations (took only several years to convince Walter to add them) which are more flexible and much better suited for this. @unittest // - this is a unit-test function void mySuperDuperTestFunction(...); There is no benefit in having all those special case features in the language which have all sorts of integration issues yet deny the usefulness of a more general solution generally accepted in the programming world, successfully used in many languages and thus also familiar to programmers coming from those languages.
Re: Are there any default dmd optimizations
On Tuesday, 26 February 2013 at 18:41:24 UTC, Andrej Mitrovic wrote: On 2/26/13, foobar f...@bar.com wrote: Rust on the other hand already integrated an ownership system and is already far ahead of D's design. Far ahead? It allows things like local variables shadowing earlier declarations: let monster_size = monster_factor * 10.0; ... let monster_size: int = 50; That's straight from the tutorial. When has anyone thought to themselves I need a new variable to store some result to, but damn, I wish I could use an existing name but use it to store a completely different type. That is an incentive to write unreadable code. And then there are things like this: Note that, if applied to an integer value, ! flips all the bits (like ~ in C). So (!2 == true)? There are plenty of complaints for both languages (it's only natural), but saying that Rust is somehow far ahead, I don't buy that one bit. It's all too easy to cherrypick features which are in one language and not in the other. I don't get what fault you find in the binary NOT operation. Regardless, my post wasn't really about specific features, (Walter actually mentioned those) but rather about the general design philosophy of D which I find lacking. Yes, it is obviously true that Rust has it own share of faults, The difference is what *principals* they use to address those faults and evolve the language. Rust is written in Rust, thus the developers themselves feel all the shortcomings, they also listen to their users and they strive to find the best way to express the semantics they want in the possibly simplest yet readable syntax possible. They think positive and build on their vision, whereas D thinks negatively based on C++'s vision. D exists for more than a decade and all it provides is slightly less hackish C++. At first, I dismissed Rust for having poor syntax (ret really? Are we back to assembly?) but lo and behold, in a very short time they considerably improved the syntax. D still argues about the exact same issues from several years ago, as if it's stuck in a time loop. This to me shows a lack of direction. I expected thing to improve lately with all those newly minted release process discussions and such, but alas the attitude hasn't shifted at all.
Re: Are there any default dmd optimizations
On Tuesday, 26 February 2013 at 19:53:11 UTC, Walter Bright wrote: On 2/25/2013 11:56 PM, foobar wrote: DDoc isn't part of the language but rather part of the compiler, nevertheless it has its downsides. [...] unittest is worse, I think you're missing something gigantic. Before D had ddoc, the documentation for Phobos was TERRIBLE - it was mostly missing, and the rest would describe something that had no resemblance to what the code did. Adding Ddoc completely revolutionized this. It's like night and day. Sure, you can pick at Ddoc's flaws all day, but without Ddoc, the Phobos documentation would have remained utter s**t. Yes, one could use Doxygen. One could hope an up-to-date version exists on all the platforms D is on. One could nag people to use it. One could argue with people who wanted to use a different doc generator. And one could look at typical C and C++ projects, which use no documentation generator at all, and pretty much have no documentation or have documentation as bad as the pre-Ddoc Phobos docs. Having Ddoc always there, always installed, always up to date, with literally zero effort, tips the balance. It gets used. It raised the bar on what is acceptable D code - it looks wrong without Ddoc documentation. By tipping the balance I mean it *revolutionized* D code. All of the above describes the benefits of having standardized documentation and I agree with that. That has nothing to do with DDoc's specific design compared to other similar efforts. A quick survey of languages shows that Ruby, Python, Java, C#, and many others all have the same benefits but non has the doc generator built into the compiler/vm with all the problems this entails. The same goes for unittest. How many C/C++ projects have you run across that have unit tests? Again, yes, you can use 3rd party tools (of which there are a plethora). You can try to use multiple libraries that use different unit test frameworks. You can look at Phobos before unittest and see that it was pretty much completely untested. Unittest in the language, always there, always installed, zero effort, completely changed the game. I'm very pleased at the depth and breadth of unittests in Phobos. I have no doubt that would not have happened without unittest. Sure, you can pick all day at the flaws of unittest, but you'd be missing the point - without builtin unittest, there'd be nothing to pick at, because people would not have unit tests. Same as above. You compare again to C++ and ignore the provably successful models of _many_ other languages. Ruby for instance really shines in this regard as its community is very much oriented towards TDD. Java has such a successful model with its JUnit that it inspired a whole bunch of clones for other languges and you completely ignore this. Instead you discuss the design of a new car based on experiences of horseback riders. Additional such problems - the AA issue which has been going own for years now. The endless discussions regarding tuples. It seems that D strives to bloat the language with needless features that really should have been standardized in the library and on the other hand tries to put in the library things that really ought to be built into the language to benefit from proper integration and syntax. A little history is in order here. AA's were built in to the language from the beginning, a result of my experience with how incredibly useful they were in javascript. This was many years before D had templates. There was no other way at the time to implement them in a nice manner (try doing it in C, for example). D's improving generics has enabled them to be redone as library features. I'm familiar with the history of AAs in D and how they came to be this horrible mess. Yet, templates in D are ancient news by now and the problem hadn't been fixed and not due to lack of effort. The problem is again - applying common c++ wisdom and trying to maintain inconsistent semantics. The latest case was the huge properties debate and its offshoots regarding ref semantics which I didn't even bother participate in. Bartosz developed an ownership system for D to address all the safety issues raised by ref *years ago* and it was rejected due to complexity. Now, Andrei tries to achieve similar safety guaranties by giving ref the semantics of borrowed pointers. It all seems to me like trying to build an airplane without wings cause they are too complex. Rust on the other hand already integrated an ownership system and is already far ahead of D's design. D had talked about macros *years ago* and rust already implemented them. Bartosz' ownership system was intended to support multithreaded programming. It was and still is too complicated. I've been working on another design which should serve the purpose and will need nearly zero effort from the programmer and it won't break anything. There was some
Re: Are there any default dmd optimizations
On Sunday, 24 February 2013 at 22:28:46 UTC, Walter Bright wrote: On 2/24/2013 12:57 PM, Andrej Mitrovic wrote: On 2/24/13, Jonathan M Davis jmdavisp...@gmx.com wrote: Yeah, which just adds the confusion, because all it does is enable debug bocks. The feature almost doesn't pay its weight. I mean technically you can use -version=Debug and then use version(Debug) blocks. All `debug` does is saves a little bit of typing. I should explain the reasoning for this. I've talked to many C/C++ programming managers. They lament that every C/C++ coding group feels compelled to reinvent their own debug macro scheme. This makes it pointlessly difficult to share code between groups. It's not that unlike how pre-C++98 code bases all had their own string class. By baking one scheme into the language, people will rarely feel a need to reinvent the wheel, and will go on to more productive uses of their time. This is a fallacy caused by the culture of c++ programmers - there is exactly *zero* benefit in baking this into the language. Yes, I agree with the sentiment that there should be a standard way to save programmers the hassle and all that. The correct solution to that is a culture of cultivating standard conventions and convention over configuration. E.g. Java has many such convections followed to a level of religious zeal, such as using camelCase everywhere and using PascalCase for types, etc, etc. None of which is _enforced by the language_. On the other hand, many major c++ libraries re-invent string even though there exists already std::string and there are even libraries that advocate _avoiding_ the use of stl entirely, all for the perceived benefit of efficiency which is a prime example of premature optimization. Even if there is efficiency gain in a specific implementation, ideally it should have been used to improve the standard stl::string but trying to change anything in the c++ standard is futile - you can't just send a pull request, you need to pass boat loads of red tape and wait a decade or two for the next version, thus causeing this major NIH attitude. All of this is to say, that instead of trying to fix the c++ culture in D, we should try to create a *better* D culture. When you're buying an airplane ticket, what do you say to the travel agent? The human reflex of I don't want to go to ___ doesn't get you a ticket anywhere. This feature is analogous - it's designed to not allow c++ misbehavior, instead of actually thinking what we do want and how best to achieve that. In fact there are many such not c++ features in D and which is why I find other languages such as rust a *much* better design and it evolves much faster because it is designed in terms of - what we want to achieve, how best to implement that.
Re: Transitioning to the new Release Process
On Saturday, 12 January 2013 at 12:20:21 UTC, Johannes Pfau wrote: Am Sat, 12 Jan 2013 09:22:27 +0100 schrieb foobar f...@bar.com: [...] Regarding pull requests targeting master, the current model *is* geared around that. Most contributions _should_ go to master (aka devel) and go through the full process. pull-requests for staging are meant for fixing regressions and critical bugs only, where there is _higher urgency_ for the fix that justifies the short-cut. Regular bug fixes should simply go through the regular process and will be released in the _next_ release. I also think targeting staging for some pull requests is not that bad. In the end it's not that bad if a pull request was accidentally merged into master instead of staging. It just means that it'll take more time for the fix to appear in a release (It'll be delayed by one release), but it won't mess anything up. Regarding where most requests go: This also depends on the project. I guess for phobos most requests are enhancements/new features and would go to master. For druntime it's mostly bugfixes, so probably more requests target staging. And for the dmd almost everything is a bug fix and could target staging. The wiki currently says all bug fixes should go to staging. This is a concession to D's rapid development. But again, it's not that important where the pull requests go. We should try to make breaking changes in master and have only harmless changes in staging, but the exact decision is always up to the contributor maintainers. But those 'minor' tweaks such as defining what exactly is merged to master and what to staging can always be made later on. Yea, I agree with the above. I'll just add two additional points: 1. Perhaps it makes sense to have more strict rules for new contributors. So Walter, Don, etc could merge straight to /staging/ but someone new will need to have a few pull requests accepted to master before they are allowed the same privilege. 2. Regarding DMD - it depends on the definition of what a bug fix is. There are many bugs regarding conflicts with the spec or unimplemented features. Even though these are listed as bugs on bugzilla they are really enhancements or new features and probably should go through an extra cycle via merging to /master/. For example, An implementation of auto ref for regular functions should really be treated as a new feature (and have a full design cycle) even though it's formally listed as a bug.
Re: Transitioning to the new Release Process
On Monday, 14 January 2013 at 10:33:56 UTC, mist wrote: On Saturday, 12 January 2013 at 12:30:05 UTC, Johannes Pfau wrote: Am Fri, 11 Jan 2013 18:54:12 +0100 schrieb mist n...@none.none: Short comment about cherry pick - it is only bad in sense that it creates separate untrackable commit with same content, which may easily result in merging issues. If there is only one-way direction for commit transitioning ( stuff goes from master to staging and LTS and never goes back ) there is nothing inherently bad about cherry pick. Having multiple commit ids for the same commit is also annoying. For example if someone bisected a regression and you want to revert a commit you have to figure out the commit id of the cherry picked commits. AFAIK reverts are content-based, so knowing any one commit id is enough. It is annoying mostly when comparison happens between two branches with those commits. Much more important point is that it complicates development process for newcomers without any reasonable benefit. And if we still gonna push for success as an open-source project, being easy understandable by an outsider is as important as a clear release process. The rule is quite simple and easy to understand though: regression fix - version branch bug fix - staging enhancement - master Ye, it is easy.. except you need to actually check out wiki page to be aware about it. At the very least we need relevant excerpts for outer devs separated to one small wiki page and set links to this page in github marked with big NB:. I don't have a reason to argue about the rest. The default is /master/ so any new dev unfamiliar with the process will just get his stuff delayed by one release which provides extra safety if you think about it. There is no _need_ to read the wiki as the process will work just fine without it. it'll just default too the longer, safer option. I really see no point in arguing this it complicates the process point any further.
Re: Transitioning to the new Release Process
On Friday, 11 January 2013 at 18:03:33 UTC, mist wrote: My understanding is that your understanding is somewhat different from initial proposal but that is where discussion has flow to since then and that makes me sad :) They very reason to have staging is to have better replacement to beta process which simply does not work good enough currently. Is good to have a single branch all the time, which some obscure project maintainer can check from time to time to make sure his stuff still compiles and fire regression bug reports if needed. He may even have add this test to own continuous integration suite (I'd do this if I had a serious D project) to be notified when stuff goes wrong without paying any constant attention. Attention is a key here. How many D projects are out there? How many of their maintainers pay close attention to newsgroup and read beta mail list? Compare this to being able to check your stuff on very next release at any moment you have time and want to. I stand at the point that for open source projects release and development processes should care most about end users and developers and least - about maintainers. Maintainers should have perfect git and process knowledge anyway, or at some scales thing are doomed to be crewed (2.061 anyone?). Thus I vote for a persistent staging branch. My understanding was that staging is worked on only during the (short) time span from initiating a new release and finalizing that release. Andrei I don't understand the problem you seem to see in the process. I've been away from the PC so couldn't respond earlier but I did manage to read most of the wiki page and I think Johnathan did a very good job explaining the various concepts. The only thing missing IMO is CI: It's already agreed that master is the development channel in the proposed process. The next logical step would be to generate nightly builds off of that branch. The staging branch is the beta channel - and also makes sense to have a periodical beta build. This depends on the release time span but something like fortnight or monthly beta builds makes sense to me. the additional manual builds described on the wiki on staging or even before an official release on the version branch will be something like RCs. Regarding pull requests targeting master, the current model *is* geared around that. Most contributions _should_ go to master (aka devel) and go through the full process. pull-requests for staging are meant for fixing regressions and critical bugs only, where there is _higher urgency_ for the fix that justifies the short-cut. Regular bug fixes should simply go through the regular process and will be released in the _next_ release.
Re: github release procedure
On Thursday, 3 January 2013 at 20:42:39 UTC, Johannes Pfau wrote: Am Thu, 03 Jan 2013 21:17:08 +0100 schrieb Rob T r...@ucora.com: On Thursday, 3 January 2013 at 19:19:49 UTC, Andrei Alexandrescu wrote: On 1/3/13 1:58 PM, Walter Bright wrote: As I suggested to Jacob, if the wiki lists git command sequences, it should be complete (like a script), and not full of assumptions about other commands that need to be inserted. I think this is a pertinent point - the process proposed at github is incomplete and scantily motivated. Can the experts make one more pass through it? Thanks, Andrei I'm rather concerned when I see comments that suggest that the purpose of the staging branch was not understood in the slightest. There's a lot of discussion on the issue here http://forum.dlang.org/thread/ka5rv5$2k60$1...@digitalmars.com Sorry, but I'm not sure if we have a consensus on some things discussed there: This is probably the best summary: http://forum.dlang.org/thread/ka5rv5$2k60$1...@digitalmars.com?page=16#post-woyboqigqbkqjxmshppn:40forum.dlang.org 4. Feature can than be further refined and _integration bugs_ can be fixed by the general dev team. What's the overhead for many small feature branches? DMD work is probably 90% small bug fixes and 10% bigger features. So most of the time there are no integration bugs and we just waste man power reviewing commits again and copying those into staging? When the dev branch is considered stable enough by the team (exact criteria to be defined later), the changes are merged to the _2nd level of integration_ - the staging branch. This allows for a wider audience to test and provide real-world feedback. The exact criteria would be kinda important. But as we have many small bugfixes which are merged every day I don't see how the master branch would suddenly get more stable. What I am most concerned about are the timespans discussed: I propose to go for a yearly release of the stable branches with one year support (In the beginning). The wiki discussion page even mentions I don't think 4 months are a ridiculously long time for staging if the release is made every 3 years. Let's clarify a bunch of things here: 1. There is no overhead with maintaining many feature brunches. 2. Feature branches can be safely removed after their contents have been merged. This is useful for avoiding clutter. 3. There is no need to re-review the _same_ code on each branch it is merged to. That's just plain stupid. 4. Chery picking is a HORRIBLE idea for managing releases and should only be used on development. Chery-picking COPIES commits and thus loses the connections in the history graph. 5. There is no problem developing bug_fixes on separate topic branches. 6. There is no problem merging back to master. 7. Let me say this again. Merges are cheap and easy in git. So are re-merges. Avoiding merges is an artifact of client-server designs such as SVN and is NOT compatible with Git's conceptual model. I suggest to read about how git works and how best to utilize its features, and NOT apply common wisdom from CVS/SVN/RCS which are based on a _completely different_ conceptual model.
Re: github release procedure
On Thursday, 3 January 2013 at 22:04:28 UTC, Jonathan M Davis wrote: On Thursday, January 03, 2013 21:42:37 Johannes Pfau wrote: What I am most concerned about are the timespans discussed: I propose to go for a yearly release of the stable branches with one year support (In the beginning). The wiki discussion page even mentions I don't think 4 months are a ridiculously long time for staging if the release is made every 3 years. That makes it sound like they want the current stuff to be marked as staging and then have some other release that sits around for a very long time being treated as somehow more stable than the staging branch. In general, there's nothing about bug fixing which is stable, and separating out bug fixes between a more stable branch and a less stable one doesn't make all that much sense. Separating out new features and not putting them in the stable branch makes sense, but that really doesn't make sense for bugs. Also, the name staging implies that it's purely for preparing a release, in which case keeping it around makes _no_ sense. Not to mention, as already mentioned, it would make more sense to simply create a new branch for each release to begin with than have a staging branch if that's what it's for. And if that's not what it's for, then it's a horrible name. - Jonathan M Davis As I explained several times before, this is a HORRIBLE idea. If each release has its own branch than a bug fix needs to be applied to _all_ such branches _manually_ and it is easy to get a situation where a fix on say version 3.1 was accidentally not merged to version 4.0 (forgotten) and suddenly the bug was unfixed. Whatever the name of this branch is, the semantics/purpose of it is to provide integration.
Re: moving away from changelog.dd?
On Tuesday, 25 December 2012 at 19:44:41 UTC, Walter Bright wrote: On 12/25/2012 11:19 AM, Jonathan M Davis wrote: On Tuesday, December 25, 2012 04:18:10 Walter Bright wrote: On 12/25/2012 3:41 AM, Jonathan M Davis wrote: I think that that's what most of us are agreed upon at this point. What is currently the WHATSNEW section will continue to be done by hand, but the LIBBUGSFIXED section will be autogenerated. WHATSNEW is a list of new features, which are (or should be) in bugzilla as enhancement requests. So, if we put a new module through the review process, we're going to go and create an ehancement request for it after the fact just so that it's in bugzilla and shows up in the automatically generated changelog? Yes. Recall that there are a pretty small number of these, so it's fair to compromise on this. That seems off to me. Bugzilla is for reporting bugs or requesting that things be added to the language or library, not for reporting everything that we do. The SCM log is for that. That log is pretty useless for anyone who wants a list of bug fixes and new features, as it is full of commits that are irrelevant to users. Also, some of those sorts of changes should probably get more prominence than they're likely to get in the middle of a list of bugzilla issues, or they may require further explanation. Full explanations were never what the changelog was for, that's why it is a list of clickable links. And it's not like it takes much time or effort to maintain the the WHATSNEW section, as it's much smaller than the bug fix section. Nor does it take much time or effort to add 3 enhancement requests to Bugzilla for new modules. Various musings, rationales, future changes, etc., should go in a separate document called releasenotes. I don't think it's viable to have a document half-generated automatically and half-editted by humans. I really don't see why not. The section with new stuff gets written by hand and the bug fix section gets created with a bugzilla query. What's so hard about that? Sure it's possible, but I prefer to keep the complexity down of generating the site. Also, releasenotes and changelog serve different purposes, it makes sense to have them be separate documents. (A future change is NOT a change to the current release.) I don't think that we've been having any problems whatsoever dealing with the WHATSNEW section. Yes, we have. Things have frequently been omitted. It seems everyone agrees there need to be an automated changelog and a hand written release-notes. I don't see a point to continue bikeshading whether they belong in a single document or two separate ones. Just pick the one that is easiest to implement! We can always add a link to the changelog from the release-notes to satisfy those that want a single document. The more important issue is whether to add bugzilla entries after the fact and whether the changelog should be geberated from Git or bugzilla. In the _current_ state of affairs yor (walter) are correct that relying on git log messages will be useless. BUT, this is only another symptom of the current broken process. The CORRECT way to implement this would be to take the actual changes from the SCM (git) on the RELEASE branch (as opposed to the development branch) and filter it to only use MERGE commits. What that does is, it ignores all the intermediate development commits that are irrelevant. Filling up bugzilla with entries that do not belong there shouldn't be the long term solution.
Re: dlang.org Library Reference
On Saturday, 22 December 2012 at 23:04:47 UTC, Andrei Alexandrescu wrote: On 12/22/12 5:10 PM, foobar wrote: On Friday, 21 December 2012 at 21:58:34 UTC, Jacob Carlborg wrote: On 2012-12-21 18:05, Andrei Alexandrescu wrote: s/remove/integrate/ s/ugly/awesome/ It's ugly that they are manually created. Over 300 lines of comments that the doc generator should be doing automatically. I would say that is far from awesome. I would add to that that duplicating both the FS and the D module system by yet another method of grouping symbols is a *horrible* notion reeks of poor design. What is FS? File system? Andrei Yes, FS is the file system. sorry if it wasn't clear. Any categorization IMO must be made *within* the language and not in comments/documentation just as other attributes such as purity and constancy are also better served being *within* the language. D has plenty of means to accomplish this: code can be organized into packages and modules and within a module, free functions can be organized within stateless structs for additional namespace categorization. Using an all encompassing algorithms module is also unhelpful as all code is essentially an algorithm to accomplish some task. This is akin to opening a store called - A store or perhaps A place to sell you stuff. As a client of said shop, I want a better description if I to buy at the shop. Even a general Clothes shop is already much better. For 3rd party it also often makes sense to have a brand name - e.g we all know what vibe.d is all about.
Re: dlang.org Library Reference
On Sunday, 23 December 2012 at 13:21:16 UTC, Andrei Alexandrescu wrote: On 12/23/12 6:44 AM, foobar wrote: Using an all encompassing algorithms module is also unhelpful as all code is essentially an algorithm to accomplish some task. This is akin to opening a store called - A store or perhaps A place to sell you stuff. That I disagree with a bit. I think it's rather clear that std.algorithm includes classic, consecrated algorithms the kind you'll find in a book entitled Algorithms. By your argument a book called Algorithms would not make sense because it would need to describe the entire computing world. So if I'm looking for sort, I'd open algorithm. If I'm looking for parsing program options, I wouldn't expect it to be in the same place. As a client of said shop, I want a better description if I to buy at the shop. Even a general Clothes shop is already much better. For 3rd party it also often makes sense to have a brand name - e.g we all know what vibe.d is all about. Such differentiation is also useful. Andrei Does it mean you agree with the rest? :) Regarding std.algorithm, the module isn't called - 'classic, consecrated algorithms the kind you'll find in a book entitled Algorithms'. It is simply called 'std.algorithm' and there are many, *many* books on algorithms. Should this module include concurrent algorithms? Should it include distributed algorithms? Should it include statistic algorithms? Should it include natural language processing algorithms? Should it include genetic algorithms? I think it's clear by now that the name does not convey what you intend it to convey. A much better and more user friendly scheme would be to classify the algorithms by their *functionality* and not by some undefined belongs to classical algorithms books relation. e.g. Sorting algorithms, Set operations, etc. Now, if I want to sort something I know to shop at the sorting algorithms outlet and don't need to spend time going over a potentially infinite list of algorithms.
Re: dlang.org Library Reference
On Friday, 21 December 2012 at 18:31:48 UTC, Sönke Ludwig wrote: Am 21.12.2012 18:05, schrieb Andrei Alexandrescu: (...) The cheat sheet in std.algorithm is unnecessary (though I liked the brief examples), but there's a lot of value in the symbols grouped by category (searching, comparison, ...) at the top. So we need to have a means to group things in the new interface. Ideally, we would invent some standard DDOC syntax to specify groups then. But generally an ungrouped list also has its advantages when you try to look something up _by name_. I've found myself in the past, skimming over the category table multiple times, looking for a certain function, until deciding that I had to guess the category first, which may not always be obvious. So maybe keeping the manual category quick index table (and maybe putting it in a separate Categories: section) is a viable option for the time being? Most modules probably wouldn't need one anyway. What also would be nice is to have the methods inline, expandable. Would that mean the Classes/Structs/... tables as f.ex. in std.datetime? So there would be a small clickable thing and all members would fly out below it as direct links? and possibly with the short description? What about different kinds of members? Only methods, all grouped by type or all in one list? I'm just asking because I don't have any preferences for how such a thing should look like. Other docs systems provide a sorted index of symbols and also the module tree can be further expanded to see the contained symbols. Both very handy features.
Re: dlang.org Library Reference
On Friday, 21 December 2012 at 21:58:34 UTC, Jacob Carlborg wrote: On 2012-12-21 18:05, Andrei Alexandrescu wrote: s/remove/integrate/ s/ugly/awesome/ It's ugly that they are manually created. Over 300 lines of comments that the doc generator should be doing automatically. I would say that is far from awesome. I would add to that that duplicating both the FS and the D module system by yet another method of grouping symbols is a *horrible* notion reeks of poor design.
Re: Next focus: PROCESS
On Friday, 21 December 2012 at 18:34:12 UTC, Rob T wrote: On Thursday, 20 December 2012 at 23:43:12 UTC, Joseph Cassman wrote: Just some food for thought. In the section about the Branching model, the wiki currently has a staging branch in addition to the master branch. From what I understand, the idea seems to be to vet a release on staging until it is considered production level and then marked as the release. Another idea could be to keep the quality of the master branch at a high level so as to be able to branch into a release at any time, directly from master. Before feature branches are merged back into master, their quality is vetted so the quality of master is maintained. This idea seems similar to what is used for the vibe.d project (http://vibed.org/temp/branch-model-small.png). My apologies if I misunderstood their process. It looks like Xamarin has been using this process for a while and it seems to be working for them. http://tirania.org/blog/archive/2011/Oct-14.html Joseph Doesn't that just turn master into staging, and turn the feature branches into a diluted and distributed version of master? If there's no common development branch to work with that integrates the most current features together, then how will such a thing ever be properly tested before going into a high quality common branch? We also need the ability to stop brand new poorly tested features from making their way into a release, so at some point a common pre-release branch needs to be frozen from receiving any new features so that it can be honed into a high quality product. If you use the master branch for such a thing, then no new features can go into it, so with master frozen, what common branch is available for the devs to merge their new work into? --rt Precisely. I think people just don't understand the purpose of these additional branches. The point being - integration. The general flow of events should be: 1. Developer has cool idea/feature which he explores on a separate private feature branch 2. During development of the feature the developer can optionally collaborate with other developers. This can be done either by pulling from other developers' repositories directly or by pushing to a branch on github. Either way, this is an ad hoc my new feature branch. 3. First level of integration - feature is complete and is merged into official first level of integration - the dev branch (consensus was to use master for that) 4. Feature can than be further refined and _integration bugs_ can be fixed by the general dev team. 5. When the dev branch is considered stable enough by the team (exact criteria to be defined later), the changes are merged to the _2nd level of integration_ - the staging branch. This allows for a wider audience to test and provide real-world feedback. 6. when the 2nd level of integration is complete, the changes are stable enough to be released and the included features finalized. Since git provides each developer with their own private copy of the entire repository there is *no need* to define any official processes prior to initial integration. The developers are free to collaborate by using ad hoc branches. The only common sense recommendation I'd give (again, NOT part of the _official process_) is to use meaningful branch names if they are meant to be shared with other people.
Re: Next focus: PROCESS
On Thursday, 20 December 2012 at 05:33:27 UTC, Rob T wrote: On Wednesday, 19 December 2012 at 21:58:12 UTC, foobar wrote: Personally, I think the whole pre-development stage needs to get looks at - Specifically having some sort of at least high-level *binding* planning - road map, mile stones, todo lists. This should give more weight to DIPs. DIPs at the moment have no weight whatsoever. The attributes showed all the major flows in the decision making process: 1. Feature idea comes up in discussion. 2. Feature was discussed heavily by the community reaching some design consensus. 3. Plan is abandoned/forgotten due to Walter's objections - not to the design but the idea itself. 4. Feature comes up again in discussion, thus returning to point 1 above in infinite loop. A big fix is in order there too, it's actually what should be fixed first but from what I've seen going on in here if we can get something even basic implemented for the development and releases that will be a *huge* step forward. Once we have some kind of formalized process in place and prove to everyone how much better things are because of it, it'll be a first by the looks of things, and from that experience the other big holes will become easier to pick out and deal with. I think we have to keep it simple for now, focus on a dev, staging, release process, implement something, work out the bugs, get people used to having it, and prove the value, then we can get on with tackling the other major issues in a similar way. There's lots of room for improvement ahead, but we need to make at least one significant step forward in a successful way before we can hope to move on to the next one. --rt I see both as going hand-in-hand, otherwise we have chicken-egg problem. We need a better process to allow more developers to contribute code more easily *and* we need better planning to provide incentive for new developer to contribute code. Implementing only the the planning provides incentive but no means. Implementing only the process provides the means but not the incentive. While improving git mastery levels is beneficial of itself, it brings no benefit to the _users_ if only Walter is still the main developer. We end up wasting Walter's time on adjusting to a new system for a hypothetical non existent system of many developers, when he already has a working system for the actual existing situation of being the sole main developer. We need an *initial high-level* design for both parts. We can define and refine the details later and we probably should defer it to later and adjust it as we go along based on experience. Arguing now on the exact time span of a release just wastes mind cycles and detracts from the important bits - reaching a consensus regarding the goals of the project and defining a general workflow that achieves those goals with minimal amount of overhead.
Re: The impoliteness of overriding methods
On Thursday, 20 December 2012 at 08:12:54 UTC, Paulo Pinto wrote: On Thursday, 20 December 2012 at 07:48:12 UTC, foobar wrote: On Thursday, 20 December 2012 at 00:07:49 UTC, H. S. Teoh wrote: On Thu, Dec 20, 2012 at 12:11:34AM +0100, Andrej Mitrovic wrote: Some interesting blog post: http://journal.stuffwithstuff.com/2012/12/19/the-impoliteness-of-overriding-methods/ It's a post about a common problem in class design, I've ran into it a few times in D too. [...] Interesting concept. So polite overriding is simply a kind of override where the derived class method has a vtable entry separate from the base class method's entry (and thus needs explicit invocation from the base class), whereas the usual impolite overriding is a kind of override where the derived class method replaces the vtable entry of the base class method. I can see use cases for both kinds of overriding. Interestingly enough, in the polite overriding case, the call to inner is undefined until it's defined in the derived class. Which means that a method that calls inner is a kind of pseudo-abstract method (since abstract methods are those that *must* be implemented by the derived class). So if we were to implement this in D, we could extend the meaning of 'abstract': class Base { // The current, usual overridable method void replaceMe() { writeln(A); } // Abstract, because chain(chainMe) is undefined until // the derived class implements it. abstract void chainMe() { writeln(B); inner.chainMe(); // call derived class method // 'inner' is a tentative // keyword writeln(C); } } class Derived : Base { override replaceMe() { writeln(D); Base.replaceMe(); writeln(E); } // Base.chainMe is abstract, so we have to implement // this method. override void chainMe() { writeln(F); } } void main() { auto d = new Derived(); d.replaceMe(); // prints D A E d.chainMe();// prints B F C } T This is trivially implemented with a simple OO design pattern in any usual OO language: class Base { public override precious() {...} private void myPrecious() { before(); precious(); after(); } } class Derived { override precious() {...} } Having syntax sugar is redundant given how simple this pattern is. No because in your example you have to write Base already for that specific use case, whereas in BETA is up to the derived class to do as it please. Have you read the article? The Beta design (btw, it's the same in smalltalk - the article is wrong on that point) is to give control to the base class. The base class in beta is written specifically for that use case and the derived has no-control. That's the entire point of this design. It is basically a restriction to allow only overriding abstract methods (with a slightly more convenient syntax)
Re: The impoliteness of overriding methods
On Thursday, 20 December 2012 at 10:22:56 UTC, Benjamin Thaut wrote: Am 20.12.2012 10:44, schrieb sclytrack: I guess in the polite version you would make the call to the derived version here. The derived version wouldn't have to call super or anything. The problem I have with the inner method is performance. With the super method you know which method to call at compile time. The call can even be inlined. With the inner method you have to do another vtable lookup for each inner call. If implemented it should be possible to choose on a per method basis which kind of overriding policy is used, in my opinion. This argument is false. With the current usual design: Base instance = new Derived(); instance.method(); // #1 With Beta design: Base instance = new Derived(); instance.method(); // #2 In case #1, the call to method itself is virtual while the call to super is not, whereas in case #2 the call to method is _not_ virtual, but the call to inner is virtual. Either way you get one virtual call. The difference is the direction of the calls.
Re: The impoliteness of overriding methods
On Thursday, 20 December 2012 at 10:15:47 UTC, Benjamin Thaut wrote: Am 20.12.2012 10:44, schrieb sclytrack: @mustcallbefore @mustcallafter Would these be automatically called in all derived versions? @autocallbefore @autocallafter I think @mustcall would suffice, because it won't compile. If it does not compile the customer will investigate what broke and fix it (hopefully) appropriately. But of course the other options would be nice too. So basically you suggest adding a language feature to cover up library developer's poorly designed API? IMO, if you want to provide a frozen API under the current inheritance design, you should use pimpl design pattern in the first place and not ask for features to solve the problem after the fact.
Re: The impoliteness of overriding methods
On Thursday, 20 December 2012 at 14:51:31 UTC, Dan wrote: On Thursday, 20 December 2012 at 07:48:12 UTC, foobar wrote: This is trivially implemented with a simple OO design pattern in any usual OO language: class Base { public override precious() {...} private void myPrecious() { before(); precious(); after(); } } class Derived { override precious() {...} } Having syntax sugar is redundant given how simple this pattern is. I think it is more than syntactic sugar and in this case it is trivial because you as a designer of Base anticipate only one level of Derived. But, assume there are to be 2, 3, 4, or more levels of derivation. In fact, maybe you don't know how many levels there will be. For a chain of B-D1-D2-D3 I don't see how you can up front get the same effect this way. At the level of D2, base will skip the implementation of precious() in D1. At the level of D3, base will skip the implementation of precious() in D1 and D2, etc. Chaining is lost beyond the first level. It is as if something is done in one direction, you want it done the other and you provide an example that does the reversion as long as there are only two entries. It is not truly a general solution. You misunderstand. It is precisely what the quote bellow says - it saves you from coming up with new names. The same pattern can be applied multiple times for the multi-derivation case you bring up, it's just needs more method names. To extend my previous example: class Derived { override precious() { beforeDerived(); furtherPrecious(); afterDerived(); } } class FurtherDerived : Derived { void furtherPrecious() {...} } Now, we get this call chain: base.myPrecious() - Derived.precious() - FurtherDerived.furtherPrecious() This can be extended ad infinitum. From the article: If you chain more than two levels of subclasses, BETA scales better because you don’t need to keep coming up with new names. Thanks Dan
Re: The impoliteness of overriding methods
On Thursday, 20 December 2012 at 19:46:25 UTC, H. S. Teoh wrote: On Thu, Dec 20, 2012 at 08:30:36PM +0100, foobar wrote: On Thursday, 20 December 2012 at 14:51:31 UTC, Dan wrote: [...] I think it is more than syntactic sugar and in this case it is trivial because you as a designer of Base anticipate only one level of Derived. But, assume there are to be 2, 3, 4, or more levels of derivation. In fact, maybe you don't know how many levels there will be. For a chain of B-D1-D2-D3 I don't see how you can up front get the same effect this way. At the level of D2, base will skip the implementation of precious() in D1. At the level of D3, base will skip the implementation of precious() in D1 and D2, etc. Chaining is lost beyond the first level. It is as if something is done in one direction, you want it done the other and you provide an example that does the reversion as long as there are only two entries. It is not truly a general solution. You misunderstand. It is precisely what the quote bellow says - it saves you from coming up with new names. The same pattern can be applied multiple times for the multi-derivation case you bring up, it's just needs more method names. To extend my previous example: class Derived { override precious() { beforeDerived(); furtherPrecious(); afterDerived(); } } class FurtherDerived : Derived { void furtherPrecious() {...} } Now, we get this call chain: base.myPrecious() - Derived.precious() - FurtherDerived.furtherPrecious() This can be extended ad infinitum. [...] But the fact that you keep having to invent new names is itself the problem. It inevitably leads to horrible APIs that consist of names suffixed by numbers: precious(), precious1(), precious2(), precious3(), ad nauseaum. Method names that are suffixed by numbers are, as a rule, an indication of bad API design. They also make your derived classes immovable around the hierarchy, because to override their parent's method, they have to use the exact name that's introduced by the parent class, otherwise they risk accidentally short-circuiting part of the chain. Whereas BETA's unification of the entire chain of calls under a single name means that it's trivial to shuffle derived classes around the hierarchy -- you're guaranteed they only overload their immediate parent's method, and it stems the inevitable tide towards the horrible number-suffixed method names. I'm not saying that the BETA approach cannot be represented by the traditional approach -- they are functionally equivalent, as you point out. It's just that for some use cases, the BETA approach is superior. (All high-level languages compile to ASM, but that doesn't mean they add no value to programming directly in ASM.) T Yeah, I agree with all of the above points and in a completely new language designed from scratch I may very well prefer the more principled Beta approach over the regular D approach. But, In our current circumstances and given that D indeed already implements a functionally equivalent feature which we are not going to remove or replace, I just don't see adding this, in essence a duplicate feature, worth the complexity cost. As Anderi phrases that - it just doesn't pull its weight. It's all a matter of trade-offs and we cannot and should not strive to put all possible feature combinations and implementation variants into D.
Re: The impoliteness of overriding methods
On Thursday, 20 December 2012 at 20:58:40 UTC, Benjamin Thaut wrote: Am 20.12.2012 20:12, schrieb foobar: This argument is false. With the current usual design: Base instance = new Derived(); instance.method(); // #1 With Beta design: Base instance = new Derived(); instance.method(); // #2 In case #1, the call to method itself is virtual while the call to super is not, whereas in case #2 the call to method is _not_ virtual, but the call to inner is virtual. Either way you get one virtual call. The difference is the direction of the calls. No its not, if you have a chain that is longer than just 1 you will have more virtual calls in the inner case. Kind Regards Benjamin Thaut well, if the library developer wants to gain full control of that long call chain than yes, it will come with a certain price. The same price if you design the same way in C++. In practice however how common are those chains and how long are they? As far as I'm aware, inheritance of concrete classes has mostly fallen out of favor nowadays so practically speaking this is still insignificant. Btw, This reminds me the OO class in university which makes it very clear that the C++/Java/C#/etc variant of inheritance is inherently flawed. It conflates two orthogonal concerns - sub-typing and sub-classing. Small-talk for example is dynamically typed so inheritance only serves the sub-classing concern. Interfaces in Java where designed to serve only the sub-typing concern. I find Rust's trait system fascinating precisely because they realized this and did not repeat the same old mistake. They haven't addressed fully the sub-classing relation yet but I'm eagerly awaiting any developments in that area.
Re: Javascript bytecode
On Wednesday, 19 December 2012 at 08:45:20 UTC, Walter Bright wrote: On 12/19/2012 12:19 AM, Max Samukha wrote: Evidently you've dismissed all of my posts in this thread on that topic :-) As you dismissed all points in favor of bytecode. And I gave detailed reasons why. Such as it being a standardized AST representation for multiple languages. CLI is all about that, which is reflected in its name. LLVM is used almost exclusively for that purpose (clang is great). My arguments were all based on the idea of distributing compiled source code in bytecode format. The idea of using some common intermediate format to tie together multiple front ends and multiple back ends is something completely different. And, surprise (!), I've done that, too. The original C compiler I wrote for many years was a multipass affair, that communicated the data from one pass to the next via an intermediate file. I was forced into such a system because DOS just didn't have enough memory to combine the passes. I dumped it when more memory became available, as it was the source of major slowdowns in the compilation process. Note that such a system need not be *bytecode* at all, it can just hand the data structure off from one pass to the next. In fact, an actual bytecode requires a serialization of the data structures and then a reconstruction of them - rather pointless. Not advocating bytecode here but you claiming it is completely useless is so D-ish :). I'm not without experience doing everything bytecode is allegedly good at. As for CLI, it is great for implementing C#. For other languages, not so much. There turned out to be no way to efficiently represent D slices in it, for example. There other part of an intermediate representation which you ignored is attaching *multiple backends* which is important for portability and the web. Applications could be written in safeD (a subset that is supposed to have no implementation defined or undefined behaviors) and compiled to such an intermediate representation (let's call it common-IR since you don't like bytecode). Now, each client platform has its own backend for our common-IR. We can have install-time compilation like in .NET or JIT as in Java or both, or maybe some other such method. Having such format allows to add distribution to the system. The serialization and de-serialization is only pointless when done on the same machine. Another usecase could be a compilation server - we can put only the front-end on client machines and do the optimizations and native code generation on the server. This can be used for example in a browser to allow D scripting. Think for instant about smart-phone browsers. the dreaded bytecode helps to solve all those use cases.
Re: Compilation strategy
On Wednesday, 19 December 2012 at 17:17:34 UTC, Dmitry Olshansky wrote: 12/19/2012 1:33 AM, Walter Bright пишет: On 12/18/2012 11:58 AM, Dmitry Olshansky wrote: The same bytecode then could be be used for external representation. Sigh, there is (again) no point to an external bytecode. BTW In the end I think I was convinced that bytecode won't buy D much. Esp considering the cost of maintaining a separate spec for it and making sure both are in sync. This argument is bogus. One of the goals of bytecode formats is to provide a common representation for many languages. That is one of the state goals for MS' CIL and LLVM. So while it's definitely true that maintaining and *additional* format and spec adds considerable costs, but more importantly this is incorrect when *reusing already existing* such formats, not to mention the benefits of interoperability with other supported languages and platforms. Consider, calling Java libraries from JRuby, using C# code in F# projects, etc. Say I want to use both Haskel and D in the same project, How would I do it? Using LLVM I should be able to - both GHC and LDC are based on LLVM.
Re: Next focus: PROCESS
On Wednesday, 19 December 2012 at 20:51:57 UTC, deadalnix wrote: On Wednesday, 19 December 2012 at 19:56:47 UTC, Rob T wrote: Do we all agree that we need a stable branch? No. Stable isn't a boolean criteria. You'll find different degree of stability going from not so stable (dev version) to very stable (dead project). The wiki already mention a process with a branch per version of the software. Let's generalize this point for the sake of reaching consensus - we need _at least one_ stable branch which is separate from staging. We are still conflicted as to what should be the maximum amount. For the record, I'm with the camp advocating at most a fixed amount countable on one hand. That's an O(1) with a very small constant as opposed to the O(n) suggestion by Andrei. I hope Andrei appreciates the order of efficiency here.
Re: Next focus: PROCESS
On Wednesday, 19 December 2012 at 21:30:44 UTC, Andrei Alexandrescu wrote: On 12/19/12 4:23 PM, foobar wrote: On Wednesday, 19 December 2012 at 20:51:57 UTC, deadalnix wrote: On Wednesday, 19 December 2012 at 19:56:47 UTC, Rob T wrote: Do we all agree that we need a stable branch? No. Stable isn't a boolean criteria. You'll find different degree of stability going from not so stable (dev version) to very stable (dead project). The wiki already mention a process with a branch per version of the software. Let's generalize this point for the sake of reaching consensus - we need _at least one_ stable branch which is separate from staging. We are still conflicted as to what should be the maximum amount. For the record, I'm with the camp advocating at most a fixed amount countable on one hand. That's an O(1) with a very small constant as opposed to the O(n) suggestion by Andrei. I hope Andrei appreciates the order of efficiency here. I agree with one stable branch. Andrei That's great! What about the other high level points summarized eloquently by H. S. Teoh? Any other high level points or goals the process should incorporate? Personally, I think the whole pre-development stage needs to get looks at - Specifically having some sort of at least high-level *binding* planning - road map, mile stones, todo lists. This should give more weight to DIPs. DIPs at the moment have no weight whatsoever. The attributes showed all the major flows in the decision making process: 1. Feature idea comes up in discussion. 2. Feature was discussed heavily by the community reaching some design consensus. 3. Plan is abandoned/forgotten due to Walter's objections - not to the design but the idea itself. 4. Feature comes up again in discussion, thus returning to point 1 above in infinite loop. ** 5. After many cycles spanning years, the community accepts that the feature will never be added despite a consensus and constant demand. 5.1 Feature is added by surprise with deviations from consensus design, optionally integrates purely with other parts of the language. 5.1.1 Feature is final! Another prime example is the auto-ref feature which we are stuck with because Walter apparently understood differently from what you intended. This is highly coupled with Walter, making it very hard to agree on a high level design and delegate its implementation to other developers. As far as I see, No major feature was ever implemented by someone other than Walter and he has final say on all design decisions. I agree with Walter's motives, he wants to stabilize the language and by resisting to feature suggestions he sets a very high bar for any major change. That is a good thing. The problem is that it all happens in his head and not in plain sight. The community has no idea what his plans are, I'm not convinced that even you get all the details. That means no planning ahead and no delegation. Had we known that Walter sign off featureX but just doesn't have the time to implement it, than it still would be on the official *binding* todo list and someone else would be able to implement this feature. As the situation now stands, no one will bother doing any significant work if it has a high chance of being entirely dismissed by Walter.
Re: Next focus: PROCESS
On Wednesday, 19 December 2012 at 21:58:12 UTC, foobar wrote: On Wednesday, 19 December 2012 at 21:30:44 UTC, Andrei Alexandrescu wrote: On 12/19/12 4:23 PM, foobar wrote: On Wednesday, 19 December 2012 at 20:51:57 UTC, deadalnix wrote: On Wednesday, 19 December 2012 at 19:56:47 UTC, Rob T wrote: Do we all agree that we need a stable branch? No. Stable isn't a boolean criteria. You'll find different degree of stability going from not so stable (dev version) to very stable (dead project). The wiki already mention a process with a branch per version of the software. Let's generalize this point for the sake of reaching consensus - we need _at least one_ stable branch which is separate from staging. We are still conflicted as to what should be the maximum amount. For the record, I'm with the camp advocating at most a fixed amount countable on one hand. That's an O(1) with a very small constant as opposed to the O(n) suggestion by Andrei. I hope Andrei appreciates the order of efficiency here. I agree with one stable branch. Andrei That's great! What about the other high level points summarized eloquently by H. S. Teoh? Any other high level points or goals the process should incorporate? Personally, I think the whole pre-development stage needs to get looks at - Specifically having some sort of at least high-level *binding* planning - road map, mile stones, todo lists. This should give more weight to DIPs. DIPs at the moment have no weight whatsoever. The attributes showed all the major flows in the decision making process: 1. Feature idea comes up in discussion. 2. Feature was discussed heavily by the community reaching some design consensus. 3. Plan is abandoned/forgotten due to Walter's objections - not to the design but the idea itself. 4. Feature comes up again in discussion, thus returning to point 1 above in infinite loop. ** 5. After many cycles spanning years, the community accepts that the feature will never be added despite a consensus and constant demand. 5.1 Feature is added by surprise with deviations from consensus design, optionally integrates purely with other parts of the language. 5.1.1 Feature is final! Another prime example is the auto-ref feature which we are stuck with because Walter apparently understood differently from what you intended. This is highly coupled with Walter, making it very hard to agree on a high level design and delegate its implementation to other developers. As far as I see, No major feature was ever implemented by someone other than Walter and he has final say on all design decisions. I agree with Walter's motives, he wants to stabilize the language and by resisting to feature suggestions he sets a very high bar for any major change. That is a good thing. The problem is that it all happens in his head and not in plain sight. The community has no idea what his plans are, I'm not convinced that even you get all the details. That means no planning ahead and no delegation. Had we known that Walter sign off featureX but just doesn't have the time to implement it, than it still would be on the official *binding* todo list and someone else would be able to implement this feature. As the situation now stands, no one will bother doing any significant work if it has a high chance of being entirely dismissed by Walter. The high-level steps as I see them: 1. The community discusses the merits and costs of the suggested feature and a consensus must be reached regarding adding such a feature. 2. An initial design must be provided - also with consensus. including this parts: 2.a. Suggested semantics of the feature - describe as precisely as possible 2.b. All interactions with other language features must be carefully examined and listed. 2.c An initial syntax agreed upon by the community. 3. Feature is implemented and after reaching some agreed upon level of stability is than field tested by the public. 3.1 Based on public feedback, feature design can be refined and bugs are fixed until consensus is reached that feature is ready to be finalized and merged to the next stable release. It's vague on purpose - the exact details of how each point above is approved is to be decided later. The main principle is that approved planned features should be listed on the road map and point to their DIP with description of their design. Rejected features are also listed as DIPs with the rationale for the rejection, this is to avoid wasting time on repeat discussing them and requesting them. Ultimate goal for all this is making the planning process as transparent as possible for the community.
Re: Next focus: PROCESS
On Wednesday, 19 December 2012 at 21:53:04 UTC, H. S. Teoh wrote: On Wed, Dec 19, 2012 at 04:48:22PM -0500, Andrei Alexandrescu wrote: On 12/19/12 4:40 PM, deadalnix wrote: On Wednesday, 19 December 2012 at 21:30:44 UTC, Andrei Alexandrescu wrote: On 12/19/12 4:23 PM, foobar wrote: [...] Let's generalize this point for the sake of reaching consensus - we need _at least one_ stable branch which is separate from staging. We are still conflicted as to what should be the maximum amount. For the record, I'm with the camp advocating at most a fixed amount countable on one hand. That's an O(1) with a very small constant as opposed to the O(n) suggestion by Andrei. I hope Andrei appreciates the order of efficiency here. I agree with one stable branch. This does conflict with the requirement you gave before about being able to support anything, as previous stable version cannot be revised. Or does stable here mean supported ? (which means we still have branch per version, but only one version is supported) Walter needs to chime in about that. One possibility is to continue using tags for marking releases, and then branch for the few important releases that we want to patch. [...] This is a good idea, to avoid cluttering the git repo with branches. (But then again, branches in git are cheap so I don't think this is really that big of a deal.) T This has nothing to do with repository size, git optimizes that anyway. This is a very good decision which I endorse (well, I suggested it in the first place..). Having a single stable branch helps integration and minimizes human error in the process.
Re: The impoliteness of overriding methods
On Thursday, 20 December 2012 at 00:07:49 UTC, H. S. Teoh wrote: On Thu, Dec 20, 2012 at 12:11:34AM +0100, Andrej Mitrovic wrote: Some interesting blog post: http://journal.stuffwithstuff.com/2012/12/19/the-impoliteness-of-overriding-methods/ It's a post about a common problem in class design, I've ran into it a few times in D too. [...] Interesting concept. So polite overriding is simply a kind of override where the derived class method has a vtable entry separate from the base class method's entry (and thus needs explicit invocation from the base class), whereas the usual impolite overriding is a kind of override where the derived class method replaces the vtable entry of the base class method. I can see use cases for both kinds of overriding. Interestingly enough, in the polite overriding case, the call to inner is undefined until it's defined in the derived class. Which means that a method that calls inner is a kind of pseudo-abstract method (since abstract methods are those that *must* be implemented by the derived class). So if we were to implement this in D, we could extend the meaning of 'abstract': class Base { // The current, usual overridable method void replaceMe() { writeln(A); } // Abstract, because chain(chainMe) is undefined until // the derived class implements it. abstract void chainMe() { writeln(B); inner.chainMe(); // call derived class method // 'inner' is a tentative // keyword writeln(C); } } class Derived : Base { override replaceMe() { writeln(D); Base.replaceMe(); writeln(E); } // Base.chainMe is abstract, so we have to implement // this method. override void chainMe() { writeln(F); } } void main() { auto d = new Derived(); d.replaceMe(); // prints D A E d.chainMe();// prints B F C } T This is trivially implemented with a simple OO design pattern in any usual OO language: class Base { public override precious() {...} private void myPrecious() { before(); precious(); after(); } } class Derived { override precious() {...} } Having syntax sugar is redundant given how simple this pattern is.
Re: Rust updates
On Tuesday, 18 December 2012 at 07:36:26 UTC, Marcel wrote: Rust designers seems to love really short keywords, this is in my opinion a bit silly. On the other hand in D you have keywords like immutable that are rather long to type. So I prefer a mid way between those two. They aren't silly, they're consistent. We have int, char, auto, they have fn, var, and val which are common these days, why not mut, pub, and priv? What is silly are the objections, such as someone saying that it's like limiting the length of identifiers. It's obviously NOTHING like that. Rust supports several types of pointers. The simplest is the unsafe pointer, written *T, which is a completely unchecked pointer type only used in unsafe code (and thus, in typical Rust code, very rarely). It's T, and it has nothing to do with unsafety. Those are silly as well. Why be consistent with the wrong choice? I really don't want to see pubs scattered around my code as my manager used to say - don't drink and code. I really like Rust's semantics and the way it progresses but there is really no valid nor sane argument for an APL inspired syntax. Syntax is meant for human consumption and should be designed accordingly. That's one of the main goals of a programming language, otherwise we all would just program straight in assembly. After all, assembly op codes and numeric addresses are much shorter than the equivalent human readable identifiers and function names.
Re: Compilation strategy
On Tuesday, 18 December 2012 at 00:15:04 UTC, H. S. Teoh wrote: On Tue, Dec 18, 2012 at 02:08:55AM +0400, Dmitry Olshansky wrote: [...] I suspect it's one of prime examples where UNIX philosophy of combining a bunch of simple (~ dumb) programs together in place of one more complex program was taken *far* beyond reasonable lengths. Having a pipe-line: preprocessor - compiler - (still?) assembler - linker where every program tries hard to know nothing about the previous ones (and be as simple as possibly can be) is bound to get inadequate results on many fronts: - efficiency scalability - cross-border error reporting and detection (linker errors? errors for expanded macro magic?) - cross-file manipulations (e.g. optimization, see _how_ LTO is done in GCC) - multiple problems from a loss of information across pipeline* The problem is not so much the structure preprocessor - compiler - assembler - linker; the problem is that these logical stages have been arbitrarily assigned to individual processes residing in their own address space, communicating via files (or pipes, whatever it may be). The fact that they are separate processes is in itself not that big of a problem, but the fact that they reside in their own address space is a big problem, because you cannot pass any information down the chain except through rudimentary OS interfaces like files and pipes. Even that wouldn't have been so bad, if it weren't for the fact that user interface (in the form of text input / object file format) has also been conflated with program interface (the compiler has to produce the input to the assembler, in *text*, and the assembler has to produce object files that do not encode any direct dependency information because that's the standard file format the linker expects). Now consider if we keep the same stages, but each stage is not a separate program but a *library*. The code then might look, in greatly simplified form, something like this: import libdmd.compiler; import libdmd.assembler; import libdmd.linker; void main(string[] args) { // typeof(asmCode) is some arbitrarily complex data // structure encoding assembly code, inter-module // dependencies, etc. auto asmCode = compiler.lex(args) .parse() .optimize() .codegen(); // Note: no stupid redundant convert to string, parse, // convert back to internal representation. auto objectCode = assembler.assemble(asmCode); // Note: linker has direct access to dependency info, // etc., carried over from asmCode - objectCode. auto executable = linker.link(objectCode); File output(outfile, w); executable.generate(output); } Note that the types asmCode, objectCode, executable, are arbitrarily complex, and may contain lazy-evaluated data structure, references to on-disk temporary storage (for large projects you can't hold everything in RAM), etc.. Dependency information in asmCode is propagated to objectCode, as necessary. The linker has full access to all info the compiler has access to, and can perform inter-module optimization, etc., by accessing information available to the *compiler* front-end, not just some crippled object file format. The root of the current nonsense is that perfectly-fine data structures are arbitrarily required to be flattened into some kind of intermediate form, written to some file (or sent down some pipe), often with loss of information, then read from the other end, interpreted, and reconstituted into other data structures (with incomplete info), then processed. In many cases, information that didn't make it through the channel has to be reconstructed (often imperfectly), and then used. Most of these steps are redundant. If the compiler data structures were already directly available in the first place, none of this baroque dance is necessary. *Semantic info on interdependency of symbols in a source file is destroyed right before the linker and thus each .obj file is included as a whole or not at all. Thus all C run-times I've seen _sidestep_ this by writing each function in its own file(!). Even this alone should have been a clear indication. While simplicity (and correspondingly size in memory) of programs was the king in 70's it's well past due. Nowadays I think is all about getting highest throughput and more powerful features. [...] Simplicity is good. Simplicity lets you modularize a very complex piece of software (a compiler that converts D source code into executables) into manageable chunks. Simplicity does not require shoe-horning modules into separate programs with separate address spaces with separate (and deficient) input/output formats. The problem isn't with
Re: Compilation strategy
On Monday, 17 December 2012 at 22:24:00 UTC, Walter Bright wrote: On 12/17/2012 2:08 PM, Dmitry Olshansky wrote: I really loved the way Turbo Pascal units were made. I wish D go the same route. Object files would then be looked at as minimal and stupid variation of module where symbols are identified by mangling (not plain meta data as (would be) in module) and no source for templates is emitted. +1 I'll bite. How is this superior to D's system? I have never used TP. *Semantic info on interdependency of symbols in a source file is destroyed right before the linker and thus each .obj file is included as a whole or not at all. Thus all C run-times I've seen _sidestep_ this by writing each function in its own file(!). Even this alone should have been a clear indication. This is done using COMDATs in C++ and D today. Honest question - If D already has all the semantic info in COMDAT sections, why do we still require additional auxiliary files? Surely, a single binary library (lib/so) should be enough to encapsulate a library without the need to re-parse the source files or additional header files? You yourself seem to agree that a single zip file is superior to what we currently have and as an aside the entire Java community agrees with use - Java Jar/War/etc formats are all renamed zip archives. Regarding the obfuscation and portability issues - the zip file can contain whatever we want. This means it should be possible to tailor the contents to support different use-cases: * provide fat-libraries as in OSX - internally store multiple binaries for different architectures, those binary objects are very hard to decompile back to source code thus answering the obfuscation need. * provide a byte-code solution to support the portability case. e.g Java byte-code or Google's pNaCL solution that relies on LLVM bit-code. Also, there are different work-flows that can be implemented - Java uses JIT to gain efficiency vs. .NET that supports install-time AOT compilation. It basically stores the native executable in a special cache.
Re: Compilation strategy
On Tuesday, 18 December 2012 at 00:48:40 UTC, Walter Bright wrote: Wow, I think that's exactly what we could use! It serves multiple optional use cases all at once! Was there a technical reason for you not getting around towards implementing, or just a lack of time? There always seemed something more important to be doing, and Andrei thought it would be better to put such a capability in rdmd rather than dmd. This is inconsistent with D's design - providing useful features built-in (docs generator, testing, profiling, etc). More over, it breaks encapsulation. This means the compiler exposes an inferior format that will later be wrapped around by a more capable packaging format, thus exposing the implementation details and adding an external dependency on that inferior format. Besides, the other compilers merge in the same front-end code so they'll gain the same feature anyway. There's no gain in separating it out to rdmd. The main question is if you approve the concept and willing to put it on the to-do list? I'm sure that if you endorse this feature someone else will come in and implement it.
Re: Next focus: PROCESS
On Sunday, 16 December 2012 at 22:43:13 UTC, David Nadlinger wrote: On Sunday, 16 December 2012 at 22:18:14 UTC, SomeDude wrote: This sounds to me like a bad idea. And indeed, I haven't heard of any other project doing this. Having release branches is a common practice for many open source projects. For example, KDE creates a branch per minor release, with patch releases being made off that branch. LLVM also has a branch for each release. David Huh? Both LLVM and KDE are developed on *subversion* and as such their work-flows are not applicable. Not to mention that KDE is vastly different in concept and goals than a programming language. Subversion is conceptually very different from git and its model imposes practical restrictions that are not relevant for git, mostly with regards to branches, merging, etc. Actions which are first class and trivial to accomplish in git. This is analogous to designing highways based on the speed properties of bicycles.
Re: Next focus: PROCESS
On Sunday, 16 December 2012 at 23:18:20 UTC, Jonathan M Davis wrote: On Sunday, December 16, 2012 11:23:57 Andrei Alexandrescu wrote: Right now we're using a tagging system for releases, implying releases are just snapshots of a continuum. But what we need is e.g. to be able to patch 2.065 to fix a bug for a client who can't upgrade right now. That means one branch per release. Well, you can still do that. You just create a branch from the tag when you need a branch. You don't have to branch from the latest. You can branch from any point on the tree, and tags provide a good marker for points to branch if you need to. Then the official release is still clearly tagged, but you can have branches based off it when you need it. It also avoids some minor overhead when patching releases is rare. My main concern though would be that the actual release needs to be clearly marked separately from any patches, so it pretty much requires a tag regardless of what you do with branches. What I would have expected that we do (though I haven't read through most of this thread or the wiki yet, so I don't know what's being proposed) would be to branch when we do beta, and that branch would be what would ultimately end up where we release from, with a tag on the commit which was the actual release. If further commits were made for specific clients after the release, then either you'd make a branch from that which was specific to that client, or you'd put them on the same branch, where'd they'd be after the tag for the release and wouldn't affect it. - Jonathan M Davis Precisely. Thank you.
Re: Next focus: PROCESS
On Monday, 17 December 2012 at 17:45:12 UTC, David Nadlinger wrote: On Monday, 17 December 2012 at 17:31:45 UTC, foobar wrote: Huh? Both LLVM and KDE are developed on *subversion* and as such their work-flows are not applicable. Not to mention that KDE is vastly different in concept and goals than a programming language. Subversion is conceptually very different from git and its model imposes practical restrictions that are not relevant for git, mostly with regards to branches, merging, etc. Actions which are first class and trivial to accomplish in git. This is analogous to designing highways based on the speed properties of bicycles. Guess what, I know that. The post by SomeDude just claimed that release branches in general are impractical and not used by open source projects, which is wrong. David At least the first part in that sentence is correct - there are more practical work flows that are just more difficult to achieve in svn. The branch per release in those projects is just a consequence of SVN limitations. hence open source projects _that use git_ don't need to follow this route. Either way, this is completely irrelevant for our purpose. The process should be designed with DVCS in mind since we already settled on this [very successful] model for D. We should avoid designing a work-flow based on other models and limited experience with git. Suggestions such as implementing specific [shell?] scripts and having branch-per-release brings no improvement over what we already have. I personally transitioned my [previous] team from ancient systems (rcs, cvs, proprietary in-house crap) to git. It requires not only memorizing a few new command line commands but also grokking a different model. Those that do, use git to great effect and greatly increase their efficiency, others simply have a ci script that calls git commit and gain nothing. At the moment we may use git commands but really we are still developing on mostly a subversion model. Walter used to accept patches and those were simply replaced by pull requests. There isn't any change in the mental model required to really benefit from a decentralized system such as git. This is what the process discussion is ultimately meant to fix.
Re: Compilation strategy
On Monday, 17 December 2012 at 04:49:46 UTC, Michel Fortin wrote: On 2012-12-17 03:18:45 +, Walter Bright newshou...@digitalmars.com said: Whether the file format is text or binary does not make any fundamental difference. I too expect the difference in performance to be negligible in binary form if you maintain the same structure. But if you're translating it to another format you can improve the structure to make it faster. If the file had a table of contents (TOC) of publicly visible symbols right at the start, you could read that table of content alone to fill symbol tables while lazy-loading symbol definitions from the file only when needed. Often, most of the file beyond the TOC wouldn't be needed at all. Having to parse and construct the syntax tree for the whole file incurs many memory allocations in the compiler, which you could avoid if the file was structured for lazy-loading. With a TOC you have very little to read from disk and very little to allocate in memory and that'll make compilation faster. More importantly, if you use only fully-qualified symbol names in the translated form, then you'll be able to load lazily privately imported modules because they'll only be needed when you need the actual definition of a symbol. (Template instantiation might require loading privately imported modules too.) And then you could structure it so a whole library could fit in one file, putting all the TOCs at the start of the same file so it loads from disk in a single read operation (or a couple of *sequential* reads). I'm not sure of the speedup all this would provide, but I'd hazard a guess that it wouldn't be so negligible when compiling a large project incrementally. Implementing any of this in the current front end would be a *lot* of work however. Precisely. That is the correct solution and is also how [turbo?] pascal units (==libs) where implemented *decades ago*. I'd like to also emphasize the importance of using a *single* encapsulated file. This prevents synchronization hazards that D inherited from the broken c/c++ model.
Re: Next focus: PROCESS
On Monday, 17 December 2012 at 21:03:04 UTC, Rob T wrote: On Monday, 17 December 2012 at 18:14:54 UTC, foobar wrote: At the moment we may use git commands but really we are still developing on mostly a subversion model. Walter used to accept patches and those were simply replaced by pull requests. There isn't any change in the mental model required to really benefit from a decentralized system such as git. This is what the process discussion is ultimately meant to fix. I think you've made a very good point. In order to make the most out of the way decentralized systems work vs a centralized one, will require an adjustment in the way people think. If we choose to follow the centralized model nothing will be gained when using a decentralized service, however centralization has its place and there's an obvious need to merge decentralized branches into a common centralize branch so that there's a common branch to use for testing and performing releases (etc). I find it's great to debate ideas in here first, not the talk page, but any conclusions or interesting points of view should be posted into the wiki talk page so that it is not lost. IMO this one should go in the wiki if only to remind people that we have the flexibility of decentralized model to take advantage of. --rt DVCS is not about centralized vs. non centralized. This is a common misunderstanding which I too had when I started using git. The actual difference is a client-server topology (CVS, SVN, etc) vs. P2P or perhaps free-form topology. By making all users equal with their own full copies of the repository, git and similar systems made the topology an aspect of the human work-flow instead of part of the technical design implementation. This gives you the freedom to have whatever topology you want - a star, a circle, whatever. For instance, Linux is developed with a web of trust. the topology represents trust relationships. Thus, all the people Linus is pulling from directly are core developers he personally trust. They in turn trust other developers, and so on and so forth. Linus's version is the semi-official release of the Linux kernel but it is not the only release. For instance, Linux distributions can have their own repositories, and Google maintains their own repository for the android fork. So in fact, there are *multiple* repositories that represent graph roots in this web of trust topology. What about D? The current git-hub repository owned by Walter and the core devs (the github organization) is the official repository. *But*, we could also treat other compilers as roots. more over, there's no requirement for developers to go through the main github repository to share and sync. E.g Walter can pull directly from Don's repository *without* going through a formal branch on github. This in fact should be *the default workflow* for internal collaboration to reduce clutter and facilitate better organization. This is why I'm arguing fiercely against having any sort of official alpha stage. There is no need standardizing this and it only mixes private developer only code and builds with builds aimed at end-users (those would be us, people writing D code and compiling with DMD). If you look on SVN servers, you often find an endless list of developer folders, test branches, experimental branches, etc, etc. As a user, this is highly annoying to figure out what branches are meant for user consumption (releases, betas, preview for a new feature) and what isn't, dev X's private place to conduct experiments. This is only a result of the client-server topology imposed by svn architecture. The official process should only standardize and focus on the points where integration is required. Everything else is much better served as being left alone. On the other hand, I think that we need to add more focus on pre/post stages of the actual coding. This means, the planning, setting priorities (aka roadmap, mile-stones, etc) as well as reducing regressions. I saw a post suggesting an automated build-bot that will run the test suit and build nightlies. What about DIPs, how do they integrate in the work-flow? I think Andrei talked about the DIPs before but I don't thik it was discussed as part of this thread.
Re: Next focus: PROCESS
On Monday, 17 December 2012 at 22:02:45 UTC, foobar wrote: On Monday, 17 December 2012 at 21:03:04 UTC, Rob T wrote: On Monday, 17 December 2012 at 18:14:54 UTC, foobar wrote: At the moment we may use git commands but really we are still developing on mostly a subversion model. Walter used to accept patches and those were simply replaced by pull requests. There isn't any change in the mental model required to really benefit from a decentralized system such as git. This is what the process discussion is ultimately meant to fix. I think you've made a very good point. In order to make the most out of the way decentralized systems work vs a centralized one, will require an adjustment in the way people think. If we choose to follow the centralized model nothing will be gained when using a decentralized service, however centralization has its place and there's an obvious need to merge decentralized branches into a common centralize branch so that there's a common branch to use for testing and performing releases (etc). I find it's great to debate ideas in here first, not the talk page, but any conclusions or interesting points of view should be posted into the wiki talk page so that it is not lost. IMO this one should go in the wiki if only to remind people that we have the flexibility of decentralized model to take advantage of. --rt DVCS is not about centralized vs. non centralized. This is a common misunderstanding which I too had when I started using git. The actual difference is a client-server topology (CVS, SVN, etc) vs. P2P or perhaps free-form topology. By making all users equal with their own full copies of the repository, git and similar systems made the topology an aspect of the human work-flow instead of part of the technical design implementation. This gives you the freedom to have whatever topology you want - a star, a circle, whatever. For instance, Linux is developed with a web of trust. the topology represents trust relationships. Thus, all the people Linus is pulling from directly are core developers he personally trust. They in turn trust other developers, and so on and so forth. Linus's version is the semi-official release of the Linux kernel but it is not the only release. For instance, Linux distributions can have their own repositories, and Google maintains their own repository for the android fork. So in fact, there are *multiple* repositories that represent graph roots in this web of trust topology. What about D? The current git-hub repository owned by Walter and the core devs (the github organization) is the official repository. *But*, we could also treat other compilers as roots. more over, there's no requirement for developers to go through the main github repository to share and sync. E.g Walter can pull directly from Don's repository *without* going through a formal branch on github. This in fact should be *the default workflow* for internal collaboration to reduce clutter and facilitate better organization. This is why I'm arguing fiercely against having any sort of official alpha stage. There is no need standardizing this and it only mixes private developer only code and builds with builds aimed at end-users (those would be us, people writing D code and compiling with DMD). If you look on SVN servers, you often find an endless list of developer folders, test branches, experimental branches, etc, etc. As a user, this is highly annoying to figure out what branches are meant for user consumption (releases, betas, preview for a new feature) and what isn't, dev X's private place to conduct experiments. This is only a result of the client-server topology imposed by svn architecture. The official process should only standardize and focus on the points where integration is required. Everything else is much better served as being left alone. On the other hand, I think that we need to add more focus on pre/post stages of the actual coding. This means, the planning, setting priorities (aka roadmap, mile-stones, etc) as well as reducing regressions. I saw a post suggesting an automated build-bot that will run the test suit and build nightlies. What about DIPs, how do they integrate in the work-flow? I think Andrei talked about the DIPs before but I don't thik it was discussed as part of this thread. I forgot to explain that the multiple roots is applicable to D as well in that we have there fully working compilers - LDC, GDC and DMD. They currently share the same front-end - GDC and LDC merge DMD's code. This situation is also sub optimal and requires manual work and has redundancies in the process. E.g. what if the LDC guys fix a bug in the shared front-end? Should this be integrated back to DMD? What if Walter comes up with a different fix?
Re: Compilation strategy
On Monday, 17 December 2012 at 22:12:01 UTC, Walter Bright wrote: On 12/17/2012 1:53 PM, Rob T wrote: I mentioned in a previous post that we should perhaps focus on making the .di concept more efficient rather than focus on obfuscation. We're not going to do obfuscation, because as I explained such cannot work, and we shouldn't do a disservice to users by pretending it does. There are many ways that *do* work, such as PIMPL, which work today and should be used by any organization wishing to obfuscate their implementation. Shorter file sizes is a potential use case, and you could even allow a distributor of byte code to optionally supply in compressed form that is automatically uncompressed when compiling, although as a trade off that would add on a small compilation performance hit. I suspect most file transport protocols already compress the data, so compressing it ourselves probably accomplishes nothing. There are also compressed filesystems, so storing files in a compressed manner likely accomplishes little. I have toyed with the idea many times, however, of having dmd support zip files. Zip files can contain an arbitrary file hierarchy, with individual files in compressed, encrypted, or plaintext at the selection of the zip builder. An entire project, or library, or collection of source modules can be distributed as a zip file, and could be compiled with nothing more than: dmd foo.zip or: dmd myfile ThirdPartyLib.zip and have it work. The advantage here is simply that everything can be contained in one simple file. The concept is simple. The files in the zip file simply replace the zip file in the command line. So, if foo.zip contains a.d, b/c.d, and d.obj, then: dmd xx foo.zip is equivalent to: unzip foo dmd xx a.d b/c.d d.obj P.S. I've also wanted to use .zip files as the .lib file format (!), as the various .lib formats have nothing over .zip files. Yes please. This is successfully used in Java, their Jar files are actually zip files that can contain: source code, binary files, resources, documentation, package meta-data, etc. This can store multiple binaries inside to support multi-arch (as in OSX). .NET assemblies accomplish similar goals (although I don't know if they are zip archives internally as well). D can support both legacy C/C++ compatible formats (lib/obj/headers) and this new dlib format.
Re: Next focus: PROCESS
On Sunday, 16 December 2012 at 15:05:58 UTC, Andrei Alexandrescu wrote: On 12/16/12 6:15 AM, Joseph Rushton Wakeling wrote: On 12/15/2012 09:39 PM, deadalnix wrote: Can we drop the LTS name ? It reminds me of ubuntu, and I clearly hope that people promoting that idea don't plan to reproduce ubuntu's scheme : - it is not suitable for a programming language (as stated 3 time now, so just read before why I won't repeat it). - ubuntu is notoriously unstable. Call them stable release cycles if you like, which is what they are intended to be. Just one tidbit of information: I talked to Walter and we want to build into the process the ability to modify any particular release. (One possibility is to do so as part of paid support for large corporate users.) That means there needs to be one branch per release. Andrei I don't see why that is a requirement (having a branch per release). We can still have a single stable branch with tags for releases and when Walter needs to provide special customizations he can always just branch off of the tagged release. This should be Walter's business and not part of the official community process. in git terms, assuming we have a tagged release of 2.61 $ git checkout -b 2.61-partner 2.61 This branches off a new branch 2.61-partner for the specific partner modification based off the contents of the 2.61 release. Also, this kinda messes with the notion of integration. A single stable branch helps prevent forgotten bug-fixes. I.e a critical bug was fixed on release N, what will ensure it will be included in release N+1? If Release N+1 is on the same branch than the bug-fix is included by default and prevented the need to perform a manual operation (a merge) that could be forgotten.
Re: OT (partially): about promotion of integers
On Wednesday, 12 December 2012 at 21:05:05 UTC, Walter Bright wrote: On 12/12/2012 2:53 AM, foobar wrote: One example that comes to mind is the future version of JavaScript is implemented in ML. Um, there are many implementations of Javascript. In fact, I have implemented it in both C++ and D. Completely besides the point. The discussion was about using ML in real life, not what you specifically chose to use. The fact that you use D has no baring on your own assertion that ML is effectively dead. Fact is _other people and organizations_ do use it to great effect. Also, I said _future version_ of JS, meaning the next version of the ECMAscript standard. ML was specifically chosen as it allows to both be efficient and verify the correctness of the implementation.
Re: Next focus: PROCESS
On Wednesday, 12 December 2012 at 01:03:59 UTC, Rob T wrote: On Tuesday, 11 December 2012 at 23:15:27 UTC, foobar wrote: By support I meant specifically _bug fixes_. You can already download all previous released versions from the website and in no way am I arguing to change that policy. Even if we ever get to a point where we don't want to keep older releases which I doubt very much (each zip is only a few MBs and therefore insignificant on today's storage) - we could still easily just checkout the specific release tagged in git and just build that. That's what I meant too, I agree with you on this point. This is precisely what I addressed bellow. we have monthly build of our staging branch - call them monthly betas that include new upcoming features that are already stable enough to be released to the public for field testing and are tentative for the next actual release but until these feature actually get to a release they hold no guaranties and can be further modified based on the wider public testing - including changes in API. Once released, they do hold such guaranties of API stability. So these monthly betas will provide preview of language changes and allow people to prepare for future changes and also provide feedback. Having a pre-release build that can be downloaded and installed would be very nice to have if that's what you mean. Currently, to get DMD 2.061 alpha I have to jump through hoops to get it to a point where it is operational, and that is not so good as it limits severely how many users will be able to test it out. See comment above. the pre-release will contain new features already stable enough to be consumes by the general public _before_ we the developers are ready to a commit finally to their API. E.g. Walter's release of DMD with attributes that was already tested and working but after release people argued about changing its syntax from [attributes] to @(attributes). developers can have their own experimental branches for their own tests and new ideas, but once a feature reaches pre-release it should already be tested and working and ready for public consumption without commiting to a final API. OK, but who has already tested it and how many people have been able to test it and comment on it? I was thinking more along the lines of how Debian does it, with a 4 staged release process: experimental = unstable = testing (pre-release) = stable. We could probably do away with a common experimental branch, leaving 3 common branches. A common unstable branch will allow more people to test out newly introduced ideas well before they become merged into pre-release, and that may help avoid problems as we're seeing with the sudden introduction of UDA's. I am hoping that we can have a pre-release version that will be stable enough to be used on real-world applications, knowing that some things can change but not in a major way. If I don't mind dealing with major changes, then I would instead make use of what's in the unstable branch, but I expect mostly compiler devs will be using unstable, and no one will be using it on anything important. I really don't care about the numbering scheme and this is irrelevant to the topic of this discussion. We are discussing the PROCESS of development. How the releases are tagged is completely beside the point and could be named after sweet delights, cat names, Parks or even digits of PI. I really don't care and it really is _not important_. This is one of those fundamental things that are required to truly understand git - versions are the _content_ (code) they contain and are identified by a hash of that content. This is pure bikesheding but why not: Why not extend the astronomical theme to releases as well? What would you say about the latest Pluto release of DMD? ;) (Yeah, I know this is already used by the eclipse project..) I'm very surprised by your comment on version numbers and I hope you are a significant minority holder of that view. How version numbers are assigned and what the number represents has to be made a defined part of the release process otherwise you'll end up with a meaningless random number or symbol (or nothing) for each new release, and the only information it will supply to you is here's a new release. I don't see that as an improvement to the current situation, it just perpetuates the existing problem where users of the D compiler have no easy way to know if a new release is a major ground breaking one, or a minor one, or just a simple bug fix. In order to find out what a new release means in terms of the magnitude of changes, one has to read through a technical change log, and read through endless forum posts, and possibly even take a look at the commit log. Why not do something better than that when it's so easy to do? For example, if I see that the stable version has been updated, I want to quickly know if it's a bug fix
Re: OT (partially): about promotion of integers
On Wednesday, 12 December 2012 at 00:43:39 UTC, H. S. Teoh wrote: On Wed, Dec 12, 2012 at 01:26:08AM +0100, foobar wrote: On Wednesday, 12 December 2012 at 00:06:53 UTC, bearophile wrote: foobar: I would enforce overflow and underflow checking semantics. Plus one or two switches to disable such checking, if/when someone wants it, to regain the C performance. (Plus some syntax way to disable/enable such checking in a small piece of code). Maybe someday Walter will change his mind about this topic :-) I don't agree that compiler switches should change language semantics. Just because you specify a certain compiler switch, it can cause unrelated breakage in some obscure library somewhere, that assumes modular arithmetic with C/C++ semantics. And this breakage will in all likelihood go *unnoticed* until your software is running on the customer's site and then it crashes horribly. And good luck debugging that, because the breakage can be very subtle, plus it's *not* in your own code, but in some obscure library code that you're not familiar with. I think a much better approach is to introduce a new type (or new types) that *does* have the requisite bounds checking and static analysis. That's what a type system is for. [...] Yeah, of course, that's why I said the C# semantics are _way_ better. (That's a self quote) btw, here's the link for SML which does not use tagged ints - http://www.standardml.org/Basis/word.html#Word8:STR:SPEC Instances of the signature WORD provide a type of unsigned integer with modular arithmetic and logical operations and conversion operations. They are also meant to give efficient access to the primitive machine word types of the underlying hardware, and support bit-level operations on integers. They are not meant to be a ``larger'' int. It's kinda too late for D to rename int to word, say, but it's not too late to introduce a new checked int type, say 'number' or something like that (you can probably think of a better name). In fact, Andrei describes a CheckedInt type that uses operator overloading, etc., to implement an in-library solution to bounds checks. You can probably expand that into a workable lightweight int replacement. By wrapping an int in a struct with custom operators, you can pretty much have an int-sized type (with value semantics, just like native ints, no less!) that does what you want, instead of the usual C/C++ int semantics. T I didn't say D should change the implementation of integers, in fact I said the exact opposite - that it's probably to late to change the semantics for D. Had D was designed from scratch than yes, I would have advocated for a different design, either the C# one or as you suggest go even further and have two distinct types (as in SML) which is even better. But by no means am I to suggest to change D semantics _now_. Sadly, it's likely to late and we can only try to paper it on top with additional library types. This isn't a perfect solutions since the compiler has builtin knowledge about int and does optimizations that will be lost with a library type.
Re: OT (partially): about promotion of integers
On Wednesday, 12 December 2012 at 00:51:19 UTC, Walter Bright wrote: On 12/11/2012 3:44 PM, foobar wrote: Thanks for proving my point. after all , you are a C++ developer, aren't you? :) No, I'm an assembler programmer. I know how the machine works, and C, C++, and D map onto that, quite deliberately. It's one reason why D supports the vector types directly. Seriously though, it _is_ a trick and a code smell. Not to me. There is no trick or smell to anyone familiar with how computers work. I'm fully aware that computers used 2's complement. I'm also am aware of the fact that the type has an unsigned label all over it. You see it right there in that 'u' prefix of 'int'. An unsigned type should semantically entail _no sign_ in its operations. You are calling a cat a dog and arguing that dogs barf? Yeah, I completely agree with that notion, except, we are still talking about _a cat_. Andrei and I have endlessly talked about this (he argued your side). The inevitable result is that signed and unsigned types *are* conflated in D, and have to be, otherwise many things stop working. For example, p[x]. What type is x? Integer signedness in D is not really a property of the data, it is only how one happens to interpret the data in a specific context. To answer you question, yes, I would enforce overflow and underflow checking semantics. Any negative result assigned to an unsigned type _is_ a logic error. you can claim that: uint a = -1; is perfectly safe and has a well defined meaning (well, for C programmers that is), but what about: uint a = b - c; what if that calculation results in a negative number? What should the compiler do? well, there are _two_ equally possible solutions: a. The overflow was intended as in the mask = -1 case; or b. The overflow is a _bug_. The user should be made aware of this and should make the decision how to handle this. This should _not_ be implicitly handled by the compiler and allow bugs go unnoticed. I think C# solved this _way_ better than C/D. C# has overflow checking off by default. It is enabled by either using a checked { } block, or with a compiler switch. I don't see that as solving the issue in any elegant or natural way, it's more of a clumsy hack. But also consider that C# does not allow pointer arithmetic, or array slicing. Both of these rely on wraparound 2's complement arithmetic. Another data point would be (S)ML which is a compiled language which requires _explicit conversions_ and has a very strong typing system. Its programs are compiled to efficient native executables and the strong typing allows both the compiler and the programmer better reasoning of the code. Thus programs are more correct and can be optimized by the compiler. In fact, several languages are implemented in ML because of its higher guaranties. ML has been around for 30-40 years, and has failed to catch on. This is precisely the point that signed and unsigned types are conflated *in D*. Other languages, namely ML chose a different design. ML chose to have two distinct types: word and int, word is for binary data and int for integer numbers. Words provide efficient access to the machine representation and have no overflow checks, ints represent numbers and do carry overflow checks. you can convert between the two and the compiler/run-time can carry special knowledge about such conversions in order to provide better optimization. in ML, array indexing is done with an int since it _is_ conceptually a number. Btw, SML was standardized in '97. I'll also dispute the claim that it hasn't caught on - there are many derived languages from it and it is just as large if not larger than the C family of languages. It has influenced many languages and it and its derivations are being used. One example that comes to mind is the future version of JavaScript is implemented in ML. So no, not forgotten but rather alive and kicking.
Re: OT (partially): about promotion of integers
On Wednesday, 12 December 2012 at 10:35:26 UTC, Walter Bright wrote: On 12/12/2012 2:33 AM, foobar wrote: This isn't a perfect solutions since the compiler has builtin knowledge about int and does optimizations that will be lost with a library type. See my reply to bearophile about that. Yeah, just saw that :) So basically you're suggesting to implement Integer and Word library types using compiler intrinsics as a way to migrate to better ML compatible semantics. This is a possible solution if it can be proven to work. Regarding performance and overflow checking, the example you give is x86 specific. What about other platforms? For example ARM is very popular nowadays in the mobile world and there are many more smart-phones out there than there are PCs. Is the same issue exists and if not (I suspect not, but really have no idea) should D be geared towards current platforms or future ones?
Re: Next focus: PROCESS
On Wednesday, 12 December 2012 at 18:25:10 UTC, Rob T wrote: On Wednesday, 12 December 2012 at 10:22:32 UTC, foobar wrote: To summarize: 2. The version scheme is meaningless. Please check out http://www.mozilla.org/en-US/firefox/channel/#firefox as an example. It's perfectly clear, you can choose what Mozilla calls a channel - i.e release or beta. I agree Firefox has a meaningless version numbering system because Firefox adopted a meaningless version numbering system. I don't understand the rational behind the decision to switch from the previous one that was meaningful. What advantage do you gain by dropping a major, minor, and revision from your version numbering system? We can put both in a two column table with high-level description of changes and links to more-detailed change logs. There's no harm in doing that, but what would be most useful is knowing if the change is a major one or a minor one or just for bug fixes. 3. Debian is a HUGE project with lots of manpower. D is not. We all know this, but that does not mean we cannot do a lot better than we're doing now, and if we can get rid of the waste, like those endless debates that cannot be resolved with one branch, then there'll effectively be more manpower available. I think it is enough to have two _publicly visible download channels_ - release and beta (testing). Those are the only two that should be formally defined. There is no need to define prior stages of development as people can just informally create their own local branches for their own experiments and they could also push them upstream to share with other developers without any requirement to list an executable on the official download page. The source code is available on github - if you wanted to you could pull whatever branch and build it yourself at your own risk. But that's almost what we have now, and it does not work and it never will work. The problem with only two official branches, is that one has to be for a stable version, and the other has to be for the new stuff, but there's two kinds of new stuff. One kind is for breaking changes, or for introducing new concepts that have not been well tested. and the other kind is for field testing new concepts that are reasonably well understood and cause no breaking changes. What real-world programmers want to have, is a reasonably stable beta version that they can use for real work - this is NOT for playing around with, but for making things work for real. They want the beta because it has something that the stable does not yet have. What these guys don't want, and cannot put up with for real world programming, is an unstable alpha, but that's what you are proposing we continue on with, which is exactly what we have now and it does not work. In addition, once the beta/alpha is close to ready to be released into stable, it has to be frozen for a few months, where no new features are added and only bug fixes continue on, but then you've just lost your unstable branch! Have a look at the thread on the introduction of UDA's to see what's going on, and ask yourself if a two branch system will solve that kind of never ending problem. 4. The only official executables on the download page are for two channels - release and beta. You can grab the latest stable release that only gets critical bug-fixes or the monthly beta that also contains preview features such as the upcoming user-defined attributes. You can also grab previous versions of both release channels by clicking the previous versions link. Anything else has zero guaranties and you are required to build yourself from source. That all works fine. What I think is glaringly missing is the unstable branch, so we need at a minimum 3 branches. --rt I really didn't want to get dragged into the versioning scheme debate as it is just bikesheding in disguise but oh well.. I'll ask in return, what's the added benefit of your scheme? I honestly see no added benefit whatsoever. There's no intrinsic benefit compared to a changelog that lists Jelly bean after Ice cream sandwich. How do you know what was added to a version? Simple, you have a what's new page that lists new major features denoted by New feature: tag and bug-fixes denoted by Bug-Fix: tag. Here's an example - http://www.mozilla.org/en-US/firefox/17.0.1/releasenotes/ Regarding the important (IMO) part of the discussion - 2 vs. 3 levels - I feel I haven't explained myself properly so let me clarify: I was taking into account what I thought was a reasonable assumption that D2 is in the process of stabilization and no major redesigns are planed. This means the Major version is 2 as in D2. My stable releases are meant to be the Minor releases on the D2 branch. These releases can introduce new backwards-compatible features and restricted breaking changes when absolutely required _over several releases_ with _a well defined migration
Re: Next focus: PROCESS
On Wednesday, 12 December 2012 at 18:33:17 UTC, Jesse Phillips wrote: On Wednesday, 12 December 2012 at 10:22:32 UTC, foobar wrote: To summarize: 2. The version scheme is meaningless. Please check out http://www.mozilla.org/en-US/firefox/channel/#firefox as an example. It's perfectly clear, you can choose what Mozilla calls a channel - i.e release or beta. This is a poor example as it doesn't show how the development team develops these versions. If we are going to have a branch supported separate from the beta/dev builds then we need a way to say that this stable version is newer but is not as new as the beta/dev. If we release 2.61 as a stable, we would then develop new features in which version? 2.62 beta 1? If so, when we release 2.61 with a bug fix which version do we release? 2.62? 2.61 stable 2? You are right that version numbers have absolutely no meaning, I don't remember if it was you, but they are also not as important as the process improvements. However if we assign meaning to numbers there can be benefit. Mozilla basically just did away with the Major version. (I say we do a Linux and leave the 2 then realize it has no meaning and up it to 3 when we reach the age of the 2.0 kernel) We should combine your beta with an added version number. 2.61.0 = bugfixes = 2.61.1 2.61.0 = newfeatures = 2.62.0 beta 1 2.62 = preparing for stabilizing = 2.62 rc1 just some thoughts. Per my answer to Rob: D2 *is* the major version. releases should be minor versions and largely backwards compatible - some evolution is allowed given some reasonable restrictions like a proper migration path over several releases. Critical bug-fixes can go directly on stable releases but nothing else. Other enhancements, new features, etc, go first on monthly beta versions and need to pass acceptance tests community approval before graduating to stable. So a big feature such as User defined attributes can spend several cycles of beta testing and can go redesigns until everyone agrees that the final design is worthy of inclusion in the next stable release.
Re: Next focus: PROCESS
On Wednesday, 12 December 2012 at 19:28:54 UTC, Rob T wrote: The beta foobar speaks of is actually a combined alpha+beta, --rt No. I have already addressed this point before. Alpha is not part of the _official_ release process. As a developer I can create my own local branch DMD-new_feature to experiment with some new idea I had. I can later on push this upstream and share my new cool feature with other developers to play with. besides other developers, users can also fetch these new branches and build themselves. This is done _before_ it matures enough to be included in beta testing.
Re: Next focus: PROCESS
On Tuesday, 11 December 2012 at 02:02:54 UTC, Andrei Alexandrescu wrote: On 12/10/12 7:19 PM, H. S. Teoh wrote: Sounds OK to me, though it seems unnecessarily complicated. FWIW there's also this: http://drewfradette.ca/a-simpler-successful-git-branching-model/ Andrei First of all - Yay! There are still a few open questions that need to be decided before a suitable process can be defined. a. Should we have more than one stable release and provide support branches? That means we have version X which is latest stable with all the latest (stable) features included and we have an older Y version that only receives bug-fixes and is intended for support (think of Ubuntu's LTE versions). If we have such additional versions, how many do we have, for how long? My opinion - (based on Walter's) you can always download a previous version of the compiler. I'd say we should _at most_ support _one_ previous stable version with critical bug fixes only. we could always decide to support ad-hoc additional specific versions, for example before we introduce major paradigm shifting changes and this also depends on available manpower. B. should we have public pre-release versions? I think we should release additional releases - call them beta, pre-release, release candidates, whatever. These are for staging changes, allowing to field test new features and language changes before they are made final. Also allowing users to adjust their code-bases. Given the above, I think the simpler flow model above looks very promising and we should adopt it with minor changes: 1. Both staging and release should be public - the website lists both the stable versions and the staging versions. 2. the development branch should be the master branch for easier integration with pull requests. The staging releases (let's call them beta) will provide previews of upcoming and experimental features to try out without the promise of a stable API and would be released _monthly_. The stable releases will be every 3-4 months and will guaranty a stable API. A user could download DMD-201212 (i.e. this month) and play around with UDA and of course report bugs, but knowing that this feature could change syntax or even be completely removed thus allowing the developers to test stuff out in the open without committing to anything.
Re: OT (partially): about promotion of integers
On Tuesday, 11 December 2012 at 16:35:39 UTC, Andrei Alexandrescu wrote: On 12/11/12 11:29 AM, eles wrote: There's a lot to be discussed on the issue. A few quick thoughts: * 32-bit integers are a sweet spot for CPU architectures. There's rarely a provision for 16- or 8-bit operations; the action is at 32- or 64-bit. Speed can be still optimized by the compiler, behind the scenes. The approach does not asks the compiler to promote everything to widest-integral, but to do the job as if. Currently, the choice of int-C as the fastest-integral instead of widest-integral move the burden from the compiler to the user. Agreed. But then that's one of them sufficiently smart compiler arguments. http://c2.com/cgi/wiki?SufficientlySmartCompiler * Then, although most 64-bit operations are as fast as 32-bit ones, transporting operands takes twice as much internal bus real estate and sometimes twice as much core real estate (i.e. there are units that do either two 32-bit ops or one 64-bit op). * The whole reserving a bit and halving the range means extra costs of operating with a basic type. Yes, there is a cost. But, as always, there is a balance between advantages and drawbacks. What is favourable? Simplicity of promotion or a supplimentary bit? A direct and natural mapping between language constructs and machine execution is very highly appreciated in the market D is in. I don't see that changing in the foreseeable future. Besides, at the end of the day, a half-approach would be to have a widest-signed-integral and a widest-unsigned-integral type and only play with those two. D has terrific abstraction capabilities. Lave primitive types alone and define a UDT that implements your desired behavior. You can always implement safe on top of fast but not the other way around. Andrei All of the above relies on the assumption that the safety problem is due to the memory layout. There are many other programming languages that solve this by using a different point of view - the problem lies in the implicit casts and not the memory layout. In other words, the culprit is code such as: uint a = -1; which compiles under C's implicit coercion rules but _really shouldn't_. The semantically correct way would be something like: uint a = 0x_; but C/C++ programmers tend to think the -1 trick is less verbose and better. Another way is to explicitly state the programmer's intention: uint a = reinterpret!uint(-1); // no run-time penalty should occur D decided to follow C's coercion rules which I think is a design mistake but one that cannot be easily changed. Perhaps as Andrei suggested, a solution would be to use a higher level Integer type defined in a library that enforces better semantics.
Re: Is there any reason why arithmetic operation on shorts and bytes return int?
On Tuesday, 11 December 2012 at 16:09:14 UTC, Andrei Alexandrescu wrote: On 12/11/12 8:24 AM, d coder wrote: No, it's a fix of a gotcha from C. The C code would just allow the assignment. Yes Andrei. But it does not look clean if you have to write: byte a, b, c; a = cast(byte) (b + c); Well I know the advantages (safety). But imagine having to write all that when working with bytes and shorts. Makes it really difficult to work with shorts and bytes in D. Value range propagation automatically avoids the need for a lot of those casts. http://www.drdobbs.com/tools/value-range-propagation/229300211 Would I be asking for too much if I ask DMD to provide a compiler flag that makes it return bytes and shorts for operations on them? That won't happen. Andrei But than we have a bug in the value range propagation algorithm. E.g in the original program: void main() { import std.stdio; ushort a = 0x55AA; ushort b = 0xAA55; writefln(%X, ~(a | b)); } (a | b) will be in the range of ushort values and ~ of that also remains in the same value range. In other words, it makes no sense that boolean ops (and, or, xor, 1's compliment, 2's compliment) will require type promotion as they cannot exceed the original width of the values. This is unlike arithmetic which can require promotion.
Re: Next focus: PROCESS
On Tuesday, 11 December 2012 at 19:57:55 UTC, Rob T wrote: On Tuesday, 11 December 2012 at 13:19:56 UTC, foobar wrote: First of all - Yay! There are still a few open questions that need to be decided before a suitable process can be defined. I'd say we should _at most_ support _one_ previous stable version with critical bug fixes only. I agree with that as well, although I think that after a new major stable release, the previously stable should be supported (at a minimum kept available for download) for some time until the new stable is fully stabilized and most people have been able to adopt it. It may be good enough to just and pick and choose if the previous stable should get certain bug fixes or not until the support period runs out. By support I meant specifically _bug fixes_. You can already download all previous released versions from the website and in no way am I arguing to change that policy. Even if we ever get to a point where we don't want to keep older releases which I doubt very much (each zip is only a few MBs and therefore insignificant on today's storage) - we could still easily just checkout the specific release tagged in git and just build that. B. should we have public pre-release versions? A lot of people will want to use the latest available changes for actual development, so the testing or pre-release branch should be public and kept reasonably stable, although anything can happen, so it's not considered stable, just stable enough given that it may be supporting new features and improvements that have been selected for the next major stable release. This is precisely what I addressed bellow. we have monthly build of our staging branch - call them monthly betas that include new upcoming features that are already stable enough to be released to the public for field testing and are tentative for the next actual release but until these feature actually get to a release they hold no guaranties and can be further modified based on the wider public testing - including changes in API. Once released, they do hold such guaranties of API stability. So these monthly betas will provide preview of language changes and allow people to prepare for future changes and also provide feedback. I think we should release additional releases - call them beta, pre-release, release candidates, whatever. These are for staging changes, allowing to field test new features and language changes before they are made final. Also allowing users to adjust their code-bases. I think you'll need at a minimum experimental branches for testing out new ideas, the main development branch witch is considered unstable (the master branch is probably best for this one as was suggested), a pre-release or testing branch that is used for preparing for the next major stable release, and of course the current stable branch which only receives bug fixes up until the next pre-release branch is merged into stable. See comment above. the pre-release will contain new features already stable enough to be consumes by the general public _before_ we the developers are ready to a commit finally to their API. E.g. Walter's release of DMD with attributes that was already tested and working but after release people argued about changing its syntax from [attributes] to @(attributes). developers can have their own experimental branches for their own tests and new ideas, but once a feature reaches pre-release it should already be tested and working and ready for public consumption without commiting to a final API. One more thing, is that we should adopt a version numbering system that is appropriate to indicate major, minor, and bug fix releases. The method of major.minor.revision can work well for us, but there may be alternatives that will work even better depending on what the process ends up being. I really don't care about the numbering scheme and this is irrelevant to the topic of this discussion. We are discussing the PROCESS of development. How the releases are tagged is completely beside the point and could be named after sweet delights, cat names, Parks or even digits of PI. I really don't care and it really is _not important_. This is one of those fundamental things that are required to truly understand git - versions are the _content_ (code) they contain and are identified by a hash of that content. This is pure bikesheding but why not: Why not extend the astronomical theme to releases as well? What would you say about the latest Pluto release of DMD? ;) (Yeah, I know this is already used by the eclipse project..) What I'd hate to see continuing, is a major new release going out with no indication in the version number that it is a major new release as opposed to a minor revision change. For example, the current DMD stable is 2.060, and the next release will be 2.061, but it includes brand new poorly tested features, and one of them
Re: OT (partially): about promotion of integers
On Tuesday, 11 December 2012 at 22:08:15 UTC, Walter Bright wrote: On 12/11/2012 10:44 AM, foobar wrote: All of the above relies on the assumption that the safety problem is due to the memory layout. There are many other programming languages that solve this by using a different point of view - the problem lies in the implicit casts and not the memory layout. In other words, the culprit is code such as: uint a = -1; which compiles under C's implicit coercion rules but _really shouldn't_. The semantically correct way would be something like: uint a = 0x_; but C/C++ programmers tend to think the -1 trick is less verbose and better. Trick? Not at all. 1. -1 is the size of an int, which varies in C. 2. -i means complement and then increment. 3. Would you allow 2-1? How about 1-1? (1-1)-1? Arithmetic in computers is different from the math you learned in school. It's 2's complement, and it's best to always keep that in mind when writing programs. Thanks for proving my point. after all , you are a C++ developer, aren't you? :) Seriously though, it _is_ a trick and a code smell. I'm fully aware that computers used 2's complement. I'm also am aware of the fact that the type has an unsigned label all over it. You see it right there in that 'u' prefix of 'int'. An unsigned type should semantically entail _no sign_ in its operations. You are calling a cat a dog and arguing that dogs barf? Yeah, I completely agree with that notion, except, we are still talking about _a cat_. To answer you question, yes, I would enforce overflow and underflow checking semantics. Any negative result assigned to an unsigned type _is_ a logic error. you can claim that: uint a = -1; is perfectly safe and has a well defined meaning (well, for C programmers that is), but what about: uint a = b - c; what if that calculation results in a negative number? What should the compiler do? well, there are _two_ equally possible solutions: a. The overflow was intended as in the mask = -1 case; or b. The overflow is a _bug_. The user should be made aware of this and should make the decision how to handle this. This should _not_ be implicitly handled by the compiler and allow bugs go unnoticed. I think C# solved this _way_ better than C/D. Another data point would be (S)ML which is a compiled language which requires _explicit conversions_ and has a very strong typing system. Its programs are compiled to efficient native executables and the strong typing allows both the compiler and the programmer better reasoning of the code. Thus programs are more correct and can be optimized by the compiler. In fact, several languages are implemented in ML because of its higher guaranties.
Re: OT (partially): about promotion of integers
On Wednesday, 12 December 2012 at 00:06:53 UTC, bearophile wrote: foobar: I would enforce overflow and underflow checking semantics. Plus one or two switches to disable such checking, if/when someone wants it, to regain the C performance. (Plus some syntax way to disable/enable such checking in a small piece of code). Maybe someday Walter will change his mind about this topic :-) Bye, bearophile Yeah, of course, that's why I said the C# semantics are _way_ better. (That's a self quote) btw, here's the link for SML which does not use tagged ints - http://www.standardml.org/Basis/word.html#Word8:STR:SPEC Instances of the signature WORD provide a type of unsigned integer with modular arithmetic and logical operations and conversion operations. They are also meant to give efficient access to the primitive machine word types of the underlying hardware, and support bit-level operations on integers. They are not meant to be a ``larger'' int.
Re: typeid() broken for interfaces?
On Wednesday, 5 December 2012 at 16:21:55 UTC, Jonathan M Davis wrote: On Wednesday, December 05, 2012 15:11:55 foobar wrote: On Tuesday, 4 December 2012 at 18:41:14 UTC, Jonathan M Davis wrote: On Tuesday, December 04, 2012 17:35:23 foobar wrote: That's a lot of duplication considering D already provides this in Object. Though per the last major discussion on const-correctness and Object, it's likely that toString, toHash, opCmp, and opEquals will be removed from Object, in which case you'd need a derived class which implemented them to use any of them. - Jonathan m Davis In other words, the plan is to pretty much deprecate Object? I hope there would be appropriate replacement before this happens. Users should be able to have a standardized API and a default implementation for these methods. Is phobos going to introduce interface such as Printable, Comparable, etc.. ? (names tentative, I'm more worried about the semantics). No. The plan is not to deprecate Object. The reality is that those functions don't need to be on Object in D, because all of the runtime stuff that relies on them can (and really should) be templatized, whereas in Java or C#, they have to put them on Object and operate through Object. What we have currently have with Object in D is a case of having copied too much from Java and C# (and templates weren't as good in D1, possibly making those functions necessary there). And having those functions on Object has created a lot of problems with regards to stuff like const. If they're there, they have to be const so that you can compare const objects, but given how D's const works, that then make certain idioms impossible in classes (e.g. lazy loading member variables and caching). const needs to work, but we can't force it on people, and putting it on Object forces it on people. Rather, it's perfectly possible for only derived classes to have those functions. They can then use the function attributes that match what they need, and stuff like druntime's opEquals or AAs will just be appropriately tempatized and work with the derived classes without needing to have any of that on Object. There's really no need to have any of that on Object. I'd have to go digging through the archives to find the last discussion on const-correctness where this was discussed in some detail, but that's the gist of it. Putting those functions on Object causes a lot of problems with regards to function attributes, and templates make actually putting those functions on Object unnecessary. - Jonathan M Davis But these are the methods of Object. So even if Object itself remains it looses its meaning. So are we going to keep Object just for backwards compatibility? Is there any point left keeping the single root design?
Re: typeid() broken for interfaces?
On Tuesday, 4 December 2012 at 18:41:14 UTC, Jonathan M Davis wrote: On Tuesday, December 04, 2012 17:35:23 foobar wrote: That's a lot of duplication considering D already provides this in Object. Though per the last major discussion on const-correctness and Object, it's likely that toString, toHash, opCmp, and opEquals will be removed from Object, in which case you'd need a derived class which implemented them to use any of them. - Jonathan m Davis In other words, the plan is to pretty much deprecate Object? I hope there would be appropriate replacement before this happens. Users should be able to have a standardized API and a default implementation for these methods. Is phobos going to introduce interface such as Printable, Comparable, etc.. ? (names tentative, I'm more worried about the semantics).
Re: typeid() broken for interfaces?
On Tuesday, 4 December 2012 at 18:41:14 UTC, Jonathan M Davis wrote: On Tuesday, December 04, 2012 17:35:23 foobar wrote: That's a lot of duplication considering D already provides this in Object. Though per the last major discussion on const-correctness and Object, it's likely that toString, toHash, opCmp, and opEquals will be removed from Object, in which case you'd need a derived class which implemented them to use any of them. - Jonathan m Davis In other words, the plan is to pretty much deprecate Object? I hope there would be appropriate replacement before this happens. Users should be able to have a standardized API and a default implementation for these methods. Is phobos going to introduce interface such as Printable, Comparable, etc.. ? (names tentative, I'm more worried about the semantics).
Re: typeid() broken for interfaces?
On Tuesday, 4 December 2012 at 18:41:14 UTC, Jonathan M Davis wrote: On Tuesday, December 04, 2012 17:35:23 foobar wrote: That's a lot of duplication considering D already provides this in Object. Though per the last major discussion on const-correctness and Object, it's likely that toString, toHash, opCmp, and opEquals will be removed from Object, in which case you'd need a derived class which implemented them to use any of them. - Jonathan m Davis In other words, the plan is to pretty much deprecate Object? I hope there would be appropriate replacement before this happens. Users should be able to have a standardized API and a default implementation for these methods. Is phobos going to introduce interfaces such as Printable, Comparable, etc.. ? (names tentative, I'm more worried about the semantics).
Re: typeid() broken for interfaces?
On Monday, 3 December 2012 at 20:59:24 UTC, Walter Bright wrote: On 12/4/2012 2:52 AM, Jacob Carlborg wrote: Note, I'm not saying that an interface should be implicitly converted to any class, only to Object. But not all interfaces come from Objects. IMO this is a design mistake - the special case is preferred over the common case which goes against the D philosophy of making the common case easy and the special case possible. All COM instances are known at _compile_time_ as they're all required to inherit from a special IUnknown interface so the compiler _knows_ if indeed an interface represents a COM instance or not. This can be used to handle this special case differently. Interface i = new Class(); Object o = i; // should work for regular interfaces The compiler can issue a compile-time error if i is COM since this is known at compile type.
Re: typeid() broken for interfaces?
On Tuesday, 4 December 2012 at 07:38:31 UTC, Maxim Fomin wrote: On Monday, 3 December 2012 at 23:53:26 UTC, deadalnix wrote: On Monday, 3 December 2012 at 21:53:47 UTC, Walter Bright wrote: I really don't know what issue you're trying to solve here. The typeid's work fine - and interfaces are not objects. Having the typeid for an interface be an object means you cannot compare typeids of one interface to another interface. You can't instantiate interface. So an underlying type MUST exist. The whole point of typeid on expression is to discover what is the dynamic type of things, otherwize you'd be using typeid(type) not typeid(expression). You cannot create interface instance with new operator because interface object is not valid until it is actually some class instance. But this does not mean neither that typeid operator for interfaces should return dynamic type nor that interface can be implicitly converted to Object - because interface instance may be invalid: import std.stdio; interface I { } void main() { I i; // should be implicitly converted Object o = cast(Object)i; writeln(typeid(o)); } and because presence of interface does not necessarily mean that some class has implemented it. This makes casting interfaces to object unsafe operation that better should require explicit cast. The above is a perfectly safe conversion. The variable i is _a reference_ to instance of I. since it was not assigned any class instance that implements I, it is initialized as _null_. In the example above: (o is null typeid(o) == typeid(Object))
Re: typeid() broken for interfaces?
On Tuesday, 4 December 2012 at 12:30:29 UTC, Paulo Pinto wrote: On Tuesday, 4 December 2012 at 12:26:53 UTC, Jacob Carlborg wrote: On 2012-12-04 09:22, Maxim Fomin wrote: And what happens if nobody implements an interface? import std.stdio; interface I { } class A { } void main() { I i; // assume this is implicit Object o = cast(Object)i; writeln(typeid(o)); } You get a segmentation fault since both i and o are null. Safe conversion class to interface requires two conditions: 1a) that class implements interface 1b) if you try to use interface variable, it must be an allocated class instance Safe conversion to Object requires: 2a) somebody in class hierarchy implements interface 2b) interface instance is actually allocated class instance You cannot really get an instance of an interface without having a class implementing it. That is, without inserting any explicit casts, which works: interface I { } class A { } void main() { A a = new A; I i = cast(I) a; Object o = cast(Object)i; writeln(typeid(a)); // A } It is possible to check 1a) but impossible in general case to check 2a). Also the first is design feature while the second is design abuse. I don't understand why it wouldn't be safe to allow implicit casts of interfaces to Object. If I want to call toString, why should I need to insert an explicit cast to Object just because I have an interface? If you want to call toSring, it should be part of the interface specification, as simple as that. Interfaces are like contracts which state what is to be expected of a certain type. -- Paulo Generally speaking you are right. But specifically regarding toString, what would you suggest? Should each and every Interface have a toString method? Should we have an IObject Interface that all classes are required to explicitly inherit? The purpose of having a root Object class is to define the _common interface of all objects_. Why else have such a class in the first place? Requiring an explicit cast to Object makes sense only in a no-single-root design such as the one in c++ which D sensibly chose not to copy. We can have a separate debate what should the root Object define, but there should not be a requirement to explicitly cast any object to it.
Re: typeid() broken for interfaces?
On Tuesday, 4 December 2012 at 13:47:39 UTC, Paulo Pinto wrote: Generally speaking you are right. But specifically regarding toString, what would you suggest? Should each and every Interface have a toString method? Yes for each interface where you intend to call toString(). That's a lot of duplication considering D already provides this in Object. Should we have an IObject Interface that all classes are required to explicitly inherit? The purpose of having a root Object class is to define the _common interface of all objects_. Why else have such a class in the first place? For languages without generics where you need a common base class to place in containers. That's only one reason. Other reasons are to provide a common interface for all objects. Anyway, we are discussing the current D design and not other possible designs such as the one in C++. Requiring an explicit cast to Object makes sense only in a no-single-root design such as the one in c++ which D sensibly chose not to copy. We can have a separate debate what should the root Object define, but there should not be a requirement to explicitly cast any object to it. The whole point of interfaces is to have explicit dependencies of methods, properties, variables across the inheritance tree. Actually there was a discussion some months ago about what methods still made sense to expose via object, given D's templates. -- Paulo Given D's _current_ design, all objects should implicitly cast to Object. It's plain common sense - If we have a root class that all other classes inherit from than it logically follows that all class instances can be implicitly safely converted back to that root class (Object). What you are arguing is whether the current design of D of defining Object makes sense in the first place. I'm arguing that _given the current design_ the language is inconsistent and has a design flaw.
Re: Fixing cyclic import static construction problems
On Thursday, 29 November 2012 at 23:02:17 UTC, Walter Bright wrote: On 11/30/2012 9:43 AM, Walter Bright wrote: It is possible for each static constructor to specify independently of the other static constructors which imports must be constructed first. But do we really want to go that far? One way to do that might be to borrow syntax from classes: static this() : std.stdio, a, c { ... } and the this static constructor only requires that modules std.stdio, a, and c be constructed first. static this() : void { ... } means it has no dependencies on other imports. static this() { ... } has the current behavior (all imported modules must be constructed first). Why not simplify? static this() { import std.stdio, a, c; // existing syntax ... } static this() { // no imports - no dependencies ... } The current behavior should just be dropped.
Re: Breaking D2 language/spec changes with D1 being discontinued in a month
On Thursday, 29 November 2012 at 09:37:57 UTC, Manu wrote: On 29 November 2012 03:48, deadalnix deadal...@gmail.com wrote: On Thursday, 29 November 2012 at 01:29:12 UTC, Jonathan M Davis wrote: Since master will almost certainly be the development branch, I don't see how that's a problem. The stable branch will be a separate branch, and whoever is managing the stable branch will merge stuff from the master branch into it. In this case, all bug fixes are mixed with new feature and then have to be separated afterward and remerged into the stable branch. This is useless work and it is likely to cause merge conflict in the stable branch. Additionnaly, this become to really suck when several new features are dev at the same time. Finally, yhis is completely inconsistent with how github work in the first place. master make sense as an unstable branch, a release candidate, a beta or whatever, but certainly not a dev branch. Why don't you document precisely what branches you think should exist, and the working merge/rebase policies. I'm actually very curious to know. Granted, major stuff like 64-bit Windows support and UDAs should probably be introduced on branches separate from master, and it's still a problem if they're not, but it won't affect the stable branch if they're not. It will become all bigfixes will be based on code that contains the new feature. Manu: This was mentioned in the group numerous times before, here's one more time to increase awareness even more: git flow - http://nvie.com/posts/a-successful-git-branching-model/ should be easily adapted for the D development process. Walter: a champion cannot solve this issue as this requires participation of all (core) developers. Otherwise we get a _lot_ of redundant after the fact maintenance work. The only way to succeed long term is to remove all single points of failures - the single master branch on the technical side, and a single decision making person (you) on the management side. It can only be possible if you agree to relinquish some control and allow other core developers to _fully_ participate. that includes - review/pull powers, managing their own branches, taking part in the decision making process as to what feature is mature enough to be released on the stable branch. No champion can do any of that as it requires your agreement and participation. Until such changes happen and D becomes _a community process_ (as I see Andrei is rightfully pushing for) there is little chance of a bigger D success. Also, just to touch the multiple compiler versions overhead you mentioned - The point of maintaining multiple branches is to _minimize_ such overhead, not increase it. This allows for easier management of features, a more gradual release process to prevent regressions and breakage on the release branch, it gives _more control_ and allows for scaling of management to more developers. more branches = less work for you.
Re: The future of UDAs.
On Thursday, 29 November 2012 at 10:25:40 UTC, Walter Bright wrote: On 11/29/2012 6:40 PM, Jacob Carlborg wrote: On 2012-11-29 03:00, Walter Bright wrote: An attribute would bring along with it the notion of having some static constructors care about dependencies and others not. A pragma would be global to the module. Why can't the attribute be global to the module? Because attributes attach to the declarations they enclose. A global attribute would be something else. What's wrong with attaching the annotation to the module declaration? i.e. @no_circular_ctors module foobar; Ideally, I'd like to have the reverse default - require an explicit import _inside_ the static ctor when a dependency actually exists. Seems to me that in the vast majority of cases this is the actual preferred choice by users and for the tiny (if any) percent that depend on the current behavior - they'll just get an easy to fix compile-error - e.g. symbol foo.bar is missing, solvable by adding the relevant import. Of course, such a change should be properly announced and documented per the other thread about the development process of D.
Re: The future of UDAs.
On Thursday, 29 November 2012 at 14:17:40 UTC, Andrei Alexandrescu wrote: On 11/29/12 6:44 AM, foobar wrote: On Thursday, 29 November 2012 at 10:25:40 UTC, Walter Bright wrote: On 11/29/2012 6:40 PM, Jacob Carlborg wrote: On 2012-11-29 03:00, Walter Bright wrote: An attribute would bring along with it the notion of having some static constructors care about dependencies and others not. A pragma would be global to the module. Why can't the attribute be global to the module? Because attributes attach to the declarations they enclose. A global attribute would be something else. What's wrong with attaching the annotation to the module declaration? i.e. @no_circular_ctors module foobar; I think this entire approach is unprincipled (aside from solving a problem that's not urgent and not important). We shouldn't focus on the _syntax_ of the completely unprincipled approach, but instead on improving it. A possibly better approach would be e.g. to do a simple analysis of the static constructor's use of symbols, and use that set to decide whether two static constructors must be ordered or not. Andrei Huh? I made the exact same observation you did that module declarations can also carry attributes. You completely ignored the main part of my post regarding what I feel would indeed be a better approach (IMO). I don't understand why you bother to answer a post you haven't bothered to read.
Re: Something needs to happen with shared, and soon.
On Saturday, 17 November 2012 at 13:22:23 UTC, Michel Fortin wrote: On 2012-11-16 18:56:28 +, Dmitry Olshansky dmitry.o...@gmail.com said: 11/16/2012 5:17 PM, Michel Fortin пишет: In case you want to protect two variables (or more) with the same mutex. For instance: Mutex m; synchronized(m) int next_id; synchronized(m) Object[int] objects_by_id; Wrap in a struct and it would be even much clearer and safer. struct ObjectRepository { int next_id; Object[int] objects_by_id; } //or whatever that combination indicates anyway synchronized ObjectRepository objeRepo; I guess that'd be fine too. snip That solution does not work in the general case. More specifically any graph-like data structure. E.g a linked-lists, trees, etc.. Think for example an insert to a shared AVL tree.
Re: function overload on full signature?
On Wednesday, 14 November 2012 at 19:12:59 UTC, Timon Gehr wrote: On 11/14/2012 06:43 PM, foobar wrote: On Tuesday, 13 November 2012 at 21:34:28 UTC, Rob T wrote: I'm wondering why overloading has been implemented to only match on the argument list rather than the full signature which includes the return type? I know I would use it if it was available. I'm not requesting this to be a feature of D, I'm only asking why it is not being done. --rt This is hardly a new idea. It was implemented in a few languages of the 70's and it proved to be adding complexity and generally not worth the trouble. I guess they just were not doing it right then. No language nowadays bothers with this based on those past lessons. Haskell. fromInteger 2 :: Float 2.0 I thought that Haskell doesn't have function overloading (which simplifies this greatly)... Anyway, I mostly meant standard imperative/OO languages. Sorry for the confusion.
Re: function overload on full signature?
On Tuesday, 13 November 2012 at 21:34:28 UTC, Rob T wrote: I'm wondering why overloading has been implemented to only match on the argument list rather than the full signature which includes the return type? I know I would use it if it was available. I'm not requesting this to be a feature of D, I'm only asking why it is not being done. --rt This is hardly a new idea. It was implemented in a few languages of the 70's and it proved to be adding complexity and generally not worth the trouble. No language nowadays bothers with this based on those past lessons.
Re: [ ArgumentList ] vs. @( ArgumentList )
On Wednesday, 7 November 2012 at 08:36:49 UTC, Jacob Carlborg wrote: On 2012-11-06 22:53, Walter Bright wrote: C++11 has had problems adding new keywords, as about every identifier somewhere has been used by someone's C++ source code, and they don't want to break existing code. So C++11 winds up with awful things like decltype. Just create a new attribute, call it builtin or something similar, which takes attributes as arguments, i.e. @builtin(shared) int a; @builtin(property) int b; I'm not suggesting that we should change the existing @shared and @property, I just used them as an example. I honestly don't get why we keep reinventing the concept of namespaces. I agree with Jonathan regarding the identifier look-up rules in D. std.algorithm.find really should be *the default* unless the user specifically aliases that to find whereas now we have the exact opposite. But even without this we still should use D's already existing namespace solution - *the module system*. We should take a lesson from other platforms such as Java and .NET where everything is neatly organized. Let's stop this global identifiers nightmare! On that note, here's some things we *should not do*: - put unrelated random stuff in object.d - add more redundant ways to define namespaces such as __identifier, builtin(identifier), @attribute(identifier), @identifier, etc, etc.. - add more @keywords because they conflict with global identifiers. - have _huge_ single modules in Phobos that contain everything and ythe kitchen sink. I still hate with passion the std.algorithm module. It's like opening a shop called A Shop or naming a newspaper Newspaper. Proper organization is not inherently evil and we should not complicate the language design to compensate our current sloppiness.
Re: [ ArgumentList ] vs. @( ArgumentList )
On Tuesday, 6 November 2012 at 20:01:27 UTC, Jacob Carlborg wrote: On 2012-11-06 20:52, Manu wrote: I'd like to re-enforce the consideration that @attribute() makes it looks like they affect the code generation somehow... they're really just annotations. I still like the syntax. I'd also like to add that the OP argument is false. Sure, the attributes themselves are just meta-data and you can use them for purely informative purposes (to annotate with documentation, author names, versions, license, etc..) but more commonly attributes are intended to be introspected on at CT or RT and used to *indirectly cause some processing*. The end result is the same and user defined attributes should be consistent with built-in ones. Syntax wise, I agree the C# version is /slightly/ more pleasant to the eye than the Java one but given the possible grammar ambiguities and the consistency with buit-ins, @(attributes) win by a landslide.
Re: Regarding hex strings
On Saturday, 20 October 2012 at 10:51:25 UTC, Denis Shelomovskij wrote: 18.10.2012 12:58, foobar пишет: IMO, this is a redundant feature that complicates the language for no benefit and should be deprecated. strings already have an escape sequence for specifying code-points \u and for ubyte arrays you can simply use: immutable(ubyte)[] data2 = [0xA1 0xB2 0xC3 0xD4]; So basically this feature gains us nothing. Maybe. Just an example of a real world code: Arrays: https://github.com/D-Programming-Language/druntime/blob/fc45de1d089a1025df60ee2eea66ba27ee0bd99c/src/core/sys/windows/dll.d#L110 vs Hex strings: https://github.com/denis-sh/hooking/blob/69105a24d77fcb6eca701282a16dd5ec7311c077/tlsfixer/ntdll.d#L130 By the way, current code isn't affected by the topic issue. I personally find the former more readable but I guess there would always be someone to disagree. As the say, YMMV.
Re: Regarding hex strings
On Saturday, 20 October 2012 at 21:03:20 UTC, H. S. Teoh wrote: On Sat, Oct 20, 2012 at 04:39:28PM -0400, Nick Sabalausky wrote: On Sat, 20 Oct 2012 14:59:27 +0200 foobar f...@bar.com wrote: On Saturday, 20 October 2012 at 10:51:25 UTC, Denis Shelomovskij wrote: Maybe. Just an example of a real world code: Arrays: https://github.com/D-Programming-Language/druntime/blob/fc45de1d089a1025df60ee2eea66ba27ee0bd99c/src/core/sys/windows/dll.d#L110 vs Hex strings: https://github.com/denis-sh/hooking/blob/69105a24d77fcb6eca701282a16dd5ec7311c077/tlsfixer/ntdll.d#L130 By the way, current code isn't affected by the topic issue. I personally find the former more readable but I guess there would always be someone to disagree. As the say, YMMV. Honestly, I can't imagine how anyone wouldn't find the latter vastly more readable. If you want vastly human readable, you want heredoc hex syntax, something like this: ubyte[] = xEND 32 2b 32 3d 34 2e 20 32 2a 32 3d 34 2e 20 32 5e 32 3d 34 2e 20 54 68 65 72 65 66 6f 72 65 2c 20 2b 2c 20 2a 2c 20 61 6e 64 20 5e 20 61 72 65 20 74 68 65 20 73 61 6d 65 20 6f 70 65 72 61 74 69 6f 6e 2e 0a 22 36 34 30 4b 20 6f 75 67 68 74 20 74 6f 20 62 65 20 65 6e 6f 75 67 68 22 20 2d 2d 20 42 69 6c 6c 20 47 2e 2c 20 31 39 38 34 2e 20 22 54 68 65 20 49 6e 74 65 72 6e 65 74 20 69 73 20 6e 6f 74 20 61 20 70 72 69 6d 61 72 79 20 67 6f 61 6c 20 66 6f 72 20 50 43 20 75 73 61 67 65 END; (I just made that syntax up, so the details are not final, but you get the idea.) I would propose supporting this in D, but then D already has way too many different ways of writing strings, some of questionable utility, so I will refrain. Of course, the above syntax might actually be implementable with a suitable mixin template that takes a compile-time string. Maybe we should lobby for such a template to go into Phobos -- that might motivate people to fix CTFE in dmd so that it doesn't consume unreasonable amounts of memory when the size of CTFE input gets moderately large (see other recent thread on this topic). T Yeah, I like this. I'd prefer brackets over quotes but it not a big dig as the qoutes in the above are not very noticeable. It should look distinct from textual strings. As you said, this could/should be implemented as a template. Vote++
Re: Regarding hex strings
On Saturday, 20 October 2012 at 21:16:44 UTC, foobar wrote: On Saturday, 20 October 2012 at 21:03:20 UTC, H. S. Teoh wrote: On Sat, Oct 20, 2012 at 04:39:28PM -0400, Nick Sabalausky wrote: On Sat, 20 Oct 2012 14:59:27 +0200 foobar f...@bar.com wrote: On Saturday, 20 October 2012 at 10:51:25 UTC, Denis Shelomovskij wrote: Maybe. Just an example of a real world code: Arrays: https://github.com/D-Programming-Language/druntime/blob/fc45de1d089a1025df60ee2eea66ba27ee0bd99c/src/core/sys/windows/dll.d#L110 vs Hex strings: https://github.com/denis-sh/hooking/blob/69105a24d77fcb6eca701282a16dd5ec7311c077/tlsfixer/ntdll.d#L130 By the way, current code isn't affected by the topic issue. I personally find the former more readable but I guess there would always be someone to disagree. As the say, YMMV. Honestly, I can't imagine how anyone wouldn't find the latter vastly more readable. If you want vastly human readable, you want heredoc hex syntax, something like this: ubyte[] = xEND 32 2b 32 3d 34 2e 20 32 2a 32 3d 34 2e 20 32 5e 32 3d 34 2e 20 54 68 65 72 65 66 6f 72 65 2c 20 2b 2c 20 2a 2c 20 61 6e 64 20 5e 20 61 72 65 20 74 68 65 20 73 61 6d 65 20 6f 70 65 72 61 74 69 6f 6e 2e 0a 22 36 34 30 4b 20 6f 75 67 68 74 20 74 6f 20 62 65 20 65 6e 6f 75 67 68 22 20 2d 2d 20 42 69 6c 6c 20 47 2e 2c 20 31 39 38 34 2e 20 22 54 68 65 20 49 6e 74 65 72 6e 65 74 20 69 73 20 6e 6f 74 20 61 20 70 72 69 6d 61 72 79 20 67 6f 61 6c 20 66 6f 72 20 50 43 20 75 73 61 67 65 END; (I just made that syntax up, so the details are not final, but you get the idea.) I would propose supporting this in D, but then D already has way too many different ways of writing strings, some of questionable utility, so I will refrain. Of course, the above syntax might actually be implementable with a suitable mixin template that takes a compile-time string. Maybe we should lobby for such a template to go into Phobos -- that might motivate people to fix CTFE in dmd so that it doesn't consume unreasonable amounts of memory when the size of CTFE input gets moderately large (see other recent thread on this topic). T Yeah, I like this. I'd prefer brackets over quotes but it not a big dig as the qoutes in the above are not very noticeable. It should look distinct from textual strings. As you said, this could/should be implemented as a template. Vote++ ** not a big deal
Re: Const ref and rvalues again...
On Friday, 19 October 2012 at 07:53:30 UTC, Jacob Carlborg wrote: On 2012-10-19 04:48, Timon Gehr wrote: Then how to specify that the value of x cannot be escaped? I'm in favour of doing it the other way round and disallow escaping of ref parameters without an unsafe cast. scope is supposed to be used to prevent this. I like Timon's idea. scope is a bad fit in that the default should be the safe option. Unfortunately this does have the potential to brake lots of code, perhaps even if we limit it to @safe code. An argument could be made that it's worth the breakage for @safe code to insure better safety.
Re: Regarding hex strings
On Friday, 19 October 2012 at 00:14:18 UTC, Nick Sabalausky wrote: On Thu, 18 Oct 2012 12:11:13 +0200 foobar f...@bar.com wrote: How often large binary blobs are literally spelled in the source code (as opposed to just being read from a file)? Frequency isn't the issue. The issues are *Is* it ever needed? and When it is needed, is it useful enough? The answer to both is most certainly yes. (Remember, D is supposed to usable as a systems language, it's not merely a high-level-app-only language.) Any real-world use cases to support this claim? Does C++ have such a feature? My limited experience with kernels is that this feature is not needed. The solution we used for this was to define an extern symbol and load it with a linker script (the binary data was of course stored in separate files). Keep in mind, the question Does it pull it's own weight? is for adding new features, not for going around gutting the language just because we can. Ok, I grant you that but remember that the whole thread started because the feature _doesn't_ work so lets rephrase - is it worth the effort to fix this feature? In any case, I'm not opposed to such a utility library, in fact I think it's a rather good idea and we already have a precedent with oct! I just don't think this belongs as a built-in feature in the language. I think monarch_dodra's test proves that it definitely needs to be built-in. It proves that DMD has bugs that should be fixed, nothing more.
Re: Regarding hex strings
On Friday, 19 October 2012 at 13:19:09 UTC, Don Clugston wrote: We can still have both (assuming the code points are valid...): string foo = \ua1\ub2\uc3; // no .dup That doesn't compile. Error: escape hex sequence has 2 hex digits instead of 4 Come on, assuming the code points are valid. It says so 4 lines above!
Re: Regarding hex strings
On Friday, 19 October 2012 at 15:07:44 UTC, Don Clugston wrote: On 19/10/12 16:07, foobar wrote: On Friday, 19 October 2012 at 13:19:09 UTC, Don Clugston wrote: We can still have both (assuming the code points are valid...): string foo = \ua1\ub2\uc3; // no .dup That doesn't compile. Error: escape hex sequence has 2 hex digits instead of 4 Come on, assuming the code points are valid. It says so 4 lines above! It isn't the same. Hex strings are the raw bytes, eg UTF8 code points. (ie, it includes the high bits that indicate the length of each char). \u makes dchars. \u00A1 is not the same as xA1 nor is it x00 A1. It's two non-zero bytes. Yes, the \u requires code points and not code-units for a specific UTF encoding, which you are correct in pointing out are four hex digits and not two. This is a very reasonable choice to prevent/reduce Unicode encoding errors. http://dlang.org/lex.html#HexString states: Hex strings allow string literals to be created using hex data. The hex data need not form valid UTF characters. I _already_ said that I consider this a major semantic bug as it violates the principle of least surprise - the programmer's expectation that the D string types which are Unicode according to the spec to, well, actually contain _valid_ Unicode and _not_ arbitrary binary data. Given the above, the design of \u makes perfect sense for _strings_ - you can use _valid_ code-points (not code units) in hex form. For general purpose binary data (i.e. _not_ UTF encoded Unicode text) I also _already_ said IMO should be either stored as ubyte[] or better yet their own types that would ensure the correct invariants for the data type, be it audio, video, or just a different text encoding. In neither case the hex-string is relevant IMO. In the former it potentially violates the type's invariant and in the latter we already have array literals. Using a malformed _string_ to initialize ubyte[] IMO is simply less readable. How did that article call such features, WAT?
Re: Regarding hex strings
On Friday, 19 October 2012 at 18:46:07 UTC, foobar wrote: On Friday, 19 October 2012 at 15:07:44 UTC, Don Clugston wrote: On 19/10/12 16:07, foobar wrote: On Friday, 19 October 2012 at 13:19:09 UTC, Don Clugston wrote: We can still have both (assuming the code points are valid...): string foo = \ua1\ub2\uc3; // no .dup That doesn't compile. Error: escape hex sequence has 2 hex digits instead of 4 Come on, assuming the code points are valid. It says so 4 lines above! It isn't the same. Hex strings are the raw bytes, eg UTF8 code points. (ie, it includes the high bits that indicate the length of each char). \u makes dchars. \u00A1 is not the same as xA1 nor is it x00 A1. It's two non-zero bytes. Yes, the \u requires code points and not code-units for a specific UTF encoding, which you are correct in pointing out are four hex digits and not two. This is a very reasonable choice to prevent/reduce Unicode encoding errors. http://dlang.org/lex.html#HexString states: Hex strings allow string literals to be created using hex data. The hex data need not form valid UTF characters. I _already_ said that I consider this a major semantic bug as it violates the principle of least surprise - the programmer's expectation that the D string types which are Unicode according to the spec to, well, actually contain _valid_ Unicode and _not_ arbitrary binary data. Given the above, the design of \u makes perfect sense for _strings_ - you can use _valid_ code-points (not code units) in hex form. For general purpose binary data (i.e. _not_ UTF encoded Unicode text) I also _already_ said IMO should be either stored as ubyte[] or better yet their own types that would ensure the correct invariants for the data type, be it audio, video, or just a different text encoding. In neither case the hex-string is relevant IMO. In the former it potentially violates the type's invariant and in the latter we already have array literals. Using a malformed _string_ to initialize ubyte[] IMO is simply less readable. How did that article call such features, WAT? I just re-checked and to clarify string literals support _three_ escape sequences: \x__ - a single byte \u - two bytes \U - four bytes So raw bytes _can_ be directly specified and I hope the compiler still verifies the string literal is valid Unicode.
Re: private is non-virtual: Stuck in C++-thinking?
On Friday, 19 October 2012 at 21:09:05 UTC, Nick Sabalausky wrote: My understanding is that this is intentionally disallowed: --- module foo; class Foo { private void func() {} } class Bar : Foo { // Disallowed: private override void func() {} } void foobar(Foo f) { f.func(); } --- If D had C++'s private, that restriction would make a lot of sense (except possibly for nested classes, but I dunno). That's because: How can you override a class you can't even access? But D doesn't have a true private in the C++ sense. Instead, there is code outside a class which *is* permitted to access private members. So am I missing something, or was the sample case above overlooked when making the private must be non-virtual decision? virtual private is an obscure C++ idiom which I think the argument for is extremely week. I think Walter made the right decision here in favor of more readable code. I'd do the following: --- module foo; class Foo { private void func() { funcImpl(); } protected void funcImpl() {} } class Bar : Foo { protected override void funcImpl() {} } void foobar(Foo f) { f.func(); } ---
Re: Regarding hex strings
On Thursday, 18 October 2012 at 02:47:42 UTC, H. S. Teoh wrote: On Thu, Oct 18, 2012 at 02:45:10AM +0200, bearophile wrote: [...] hex strings are useful, but I think they were invented in D1 when strings were convertible to char[]. But today they are an array of immutable UFT-8, so I think this default type is not so useful: void main() { string data1 = xA1 B2 C3 D4; // OK immutable(ubyte)[] data2 = xA1 B2 C3 D4; // error } test.d(3): Error: cannot implicitly convert expression (\xa1\xb2\xc3\xd4) of type string to ubyte[] [...] Yeah I think hex strings would be better as ubyte[] by default. More generally, though, I think *both* of the above lines should be equally accepted. If you write xA1 B2 C3 in the context of initializing a string, then the compiler should infer the type of the literal as string, and if the same literal occurs in the context of, say, passing a ubyte[], then its type should be inferred as ubyte[], NOT string. T IMO, this is a redundant feature that complicates the language for no benefit and should be deprecated. strings already have an escape sequence for specifying code-points \u and for ubyte arrays you can simply use: immutable(ubyte)[] data2 = [0xA1 0xB2 0xC3 0xD4]; So basically this feature gains us nothing.
Re: Const ref and rvalues again...
On Thursday, 18 October 2012 at 06:11:26 UTC, monarch_dodra wrote: On Thursday, 18 October 2012 at 04:30:17 UTC, Jonathan M Davis wrote: On Thursday, October 18, 2012 06:24:08 jerro wrote: What would be the problem with const ref taking rvalues? Read the thread that I already linked to: http://forum.dlang.org/thread/4f84d6dd.5090...@digitalmars.com - Jonathan M Davis I read the thread, and not a single one of the problematic cases are actually valid C++. Yes: the faulty MSVC has taught people to do retarded things, or be afraid of things that were illegal to begin with (in particular, pass an rvalue to a ref, WHICH IS ILLEGAL IN C++), such as increment(5). There is actually nothing wrong with creating a temporary when something is bound to a const ref, provided the compiler follows the rules: *Only LValues with an EXACT type match may be passed to a reference. *In regards to *const* references, RValues may be copied in a temporary, and that temporary bound the the ref. I'm not saying we particularly *need* this in D (C++ has a by ref paradigm that makes it more important, but D *rarelly* ever passes by const ref). But if the compiler respects the above two rules (which it should), then RValue to const ref is both perfectly doable and safe (as safe as refs get anyways). By allowing the the C++ semantics the function looses semantic information - whether the actual parameter was lvalue or rvalue. This semantic info can be used bot for compiler optimizations and move semantics. This is the reason C++11 added references. General question (might not be relevant to current design of D): How about leaving the decision to the compiler and let the programmer only specify usage intent? E.g.: (I'm speaking semantics here, not syntax) void foo(const Type t); // 1. I only read the value void foo (mutate Type t); // 2. I want to also mutate the actual parameter void foo (move Type t); // 3. I want to move the actual parameter In case 1 above, the compiler is free to pass lvalues by const and rvalues by value or perhaps optimize above certain size to const too. In case 2, the compiler passes a ref to lvalue, rvalues are not accepted at CT. If I want move semantics, I can use option 3 which accepts rvalues by ref. btw, what's the correct semantics for lvalues here? What do you think?
Re: Regarding hex strings
On Thursday, 18 October 2012 at 09:42:43 UTC, monarch_dodra wrote: On Thursday, 18 October 2012 at 08:58:57 UTC, foobar wrote: IMO, this is a redundant feature that complicates the language for no benefit and should be deprecated. strings already have an escape sequence for specifying code-points \u and for ubyte arrays you can simply use: immutable(ubyte)[] data2 = [0xA1 0xB2 0xC3 0xD4]; So basically this feature gains us nothing. Have you actually ever written code that requires using code points? This feature is a *huge* convenience for when you do. Just compare: string nihongo1 = xe697a5 e69cac e8aa9e; string nihongo2 = \ue697a5\ue69cac\ue8aa9e; ubyte[] nihongo3 = [0xe6, 0x97, 0xa5, 0xe6, 0x9c, 0xac, 0xe8, 0xaa, 0x9e]; BTW, your data2 doesn't compile. I didn't try to compile it :) I just rewrote berophile's example with 0x prefixes. How often do you actually need to write code-point _literals_ in your code? I'm not arguing that it isn't convenient. My question would be rather Anderi's does it pull it's own weight? meaning does the added complexity in the language and having more than one way for doing something worth that convenience? Seems to me this is in the same ballpark as the built-in complex numbers. Sure it's nice to be able to write 4+5i instead of complex(4,5) but how frequently do you actually ever need the _literals_ even in complex computational heavy code?
Re: Regarding hex strings
On Thursday, 18 October 2012 at 10:05:06 UTC, bearophile wrote: The docs say: http://dlang.org/lex.html Hex strings allow string literals to be created using hex data. The hex data need not form valid UTF characters. But this code: void main() { immutable ubyte[4] data = xF9 04 C1 E2; } Gives me: temp.d(2): Error: Outside Unicode code space Are the docs correct? -- foobar: Seems to me this is in the same ballpark as the built-in complex numbers. Sure it's nice to be able to write 4+5i instead of complex(4,5) but how frequently do you actually ever need the _literals_ even in complex computational heavy code? Compared to oct!5151151511, one problem with code like this is that binary blobs are sometimes large, so supporting a x syntax is better: immutable ubyte[4] data = hex!F9 04 C1 E2; Bye, bearophile How often large binary blobs are literally spelled in the source code (as opposed to just being read from a file)? In any case, I'm not opposed to such a utility library, in fact I think it's a rather good idea and we already have a precedent with oct! I just don't think this belongs as a built-in feature in the language.
Re: Regarding hex strings
On Thursday, 18 October 2012 at 10:11:14 UTC, foobar wrote: On Thursday, 18 October 2012 at 10:05:06 UTC, bearophile wrote: The docs say: http://dlang.org/lex.html Hex strings allow string literals to be created using hex data. The hex data need not form valid UTF characters. This is especially a good reason to remove this feature as it breaks the principle of least surprise and I consider it a major bug, not a feature. I expect D's strings which are by definition Unicode to _only_ ever allow _valid_ Unicode. It makes no sense what so ever to allow this nasty back-door. Other text encoding should be either stored and treated as binary data (ubyte[]) or better yet stored in their own types that will ensure those encodings' invariants.
Re: Regarding hex strings
On Thursday, 18 October 2012 at 14:29:57 UTC, Don Clugston wrote: On 18/10/12 10:58, foobar wrote: On Thursday, 18 October 2012 at 02:47:42 UTC, H. S. Teoh wrote: On Thu, Oct 18, 2012 at 02:45:10AM +0200, bearophile wrote: [...] hex strings are useful, but I think they were invented in D1 when strings were convertible to char[]. But today they are an array of immutable UFT-8, so I think this default type is not so useful: void main() { string data1 = xA1 B2 C3 D4; // OK immutable(ubyte)[] data2 = xA1 B2 C3 D4; // error } test.d(3): Error: cannot implicitly convert expression (\xa1\xb2\xc3\xd4) of type string to ubyte[] [...] Yeah I think hex strings would be better as ubyte[] by default. More generally, though, I think *both* of the above lines should be equally accepted. If you write xA1 B2 C3 in the context of initializing a string, then the compiler should infer the type of the literal as string, and if the same literal occurs in the context of, say, passing a ubyte[], then its type should be inferred as ubyte[], NOT string. T IMO, this is a redundant feature that complicates the language for no benefit and should be deprecated. strings already have an escape sequence for specifying code-points \u and for ubyte arrays you can simply use: immutable(ubyte)[] data2 = [0xA1 0xB2 0xC3 0xD4]; So basically this feature gains us nothing. That is not the same. Array literals are not the same as string literals, they have an implicit .dup. See my recent thread on this issue (which unfortunately seems have to died without a resolution, people got hung up about trailing null characters without apparently noticing the more important issue of the dup). I don't see how that detail is relevant to this discussion as I was not arguing against string literals or array literals in general. We can still have both (assuming the code points are valid...): string foo = \ua1\ub2\uc3; // no .dup and: ubyte[3] goo = [0xa1, 0xb2, 0xc3]; // implicit .dup
Re: Import improvement
On Wednesday, 17 October 2012 at 15:16:12 UTC, Andrei Alexandrescu wrote: On 10/16/12 2:49 AM, Jacob Carlborg wrote: On 2012-10-16 02:10, Peter Alexander wrote: It's cute, but I think it is terribly misleading. I wouldn't recommend that to anyone. I agree. I'm using foo.bar._, that's the same used by Scala. Sounds good. Arbitrary + precedent arbitrary. Andrei Let's be accurate here: Meaningful Arbitrary + precedent arbitrary. If I want to truly import an _entire_ package than both: import package.all; import package.*; make sense/ meaningful. If I want to have a special file that includes specific public imports for the package's public API than it should be called appropriately. e.g: import package.api; I've seen such usage of an api package in Google's Android platform for instance.
Re: D seems interesting, but...
On Monday, 15 October 2012 at 13:11:29 UTC, bearophile wrote: Adam D. Ruppe: You could just version it: version(foo_main) void main() {} That's not good enough. What I as talking about is: when the D compilers know a module is the main module, it defines a _standard_ version boolean flag, named like is_main_module as true. And it gives a compiler error if it can't find a main. Otherwise is_main_module is false. It's meant to be used as: module modulea; int foo() { return 0; } static if (is_main_module) { unittest {} void main() { // demo code import std.stdio; writeln(foo()); } } module moduleb; import modulea; int bar() { return 1; } static if (is_main_module) { unittest {} void main() { // demo code import std.stdio; writeln(foo()); writeln(bar()); } } When you compile modulea, defines its is_main_module as true, it runs its unittests (if you have used -unittest), and its main, that is a demo for the A module. If you compile the moduleb (with rdmd or something), it knows moduleb has to contain the main, it defines is_main_module=true in moduleb and defines is_main_module=false for modulea. So it compiles the main of moduleb and ignores the main of modulea. So it runs the demo code for moduleb only. Using a non-standard user-defined version as you suggest misses all this, and it's not good enough. Standardization and automation is important here. Bye, bearophile I'm sorry to say but that *is* a _horrible_ _hack_. It looks almost as awful as it does in python with the underscores. Java has the correct DRY solution - each class can define a static main method but the compiler only uses the one specified by a compiler switch. The above basically asks the programmer to endlessly repeat the same trivial implementation boilerplate that should be written just once _in_ the compiler.
Re: D seems interesting, but...
On Monday, 15 October 2012 at 15:22:38 UTC, Andrei Alexandrescu wrote: snip Yes, this is a nice thing Java, .NET and Python have. Wonder if a simple convention would suffice, e.g. every module that wanna defines a moduleMain(string[] args) and then you have one module main.d that has: void main(string[] args) { import wuddever; moduleMain(args); } Andrei Great idea! But why add another (redundant) level of indirection? It should go in the C main in druntime together with a mechanism to call the correct D main, by e.g. reading the module name from the command line.