digitalmars.D - Is D a cult?
- "Jane Doe" <JanisD comcast.net> Mar 05 2010
- "Nick Sabalausky" <a a.a> Mar 05 2010
- Justin Johansson <no spam.com> Mar 06 2010
- FeepingCreature <default_357-line yahoo.de> Mar 06 2010
- Bane <branimir.milosavljevic gmail.com> Mar 06 2010
- div0 <div0 users.sourceforge.net> Mar 06 2010
- Steve Teale <steve.teale britseyeview.com> Mar 06 2010
- Chad J <chadjoan __spam.is.bad__gmail.com> Mar 06 2010
- BCS <none anon.com> Mar 06 2010
- Bane <branimir.milosavljevic gmail.com> Mar 07 2010
- Lutger <lutger.blijdestijn gmail.com> Mar 07 2010
- Lutger <lutger.blijdestijn gmail.com> Mar 07 2010
- Walter Bright <newshound1 digitalmars.com> Mar 07 2010
- bearophile <bearophileHUGS lycos.com> Mar 07 2010
- =?UTF-8?B?UGVsbGUgTcOlbnNzb24=?= <pelle.mansson gmail.com> Mar 07 2010
- Walter Bright <newshound1 digitalmars.com> Mar 07 2010
- Walter Bright <newshound1 digitalmars.com> Mar 07 2010
- Walter Bright <newshound1 digitalmars.com> Mar 08 2010
- James Iry <jamesiry gmail.com> Mar 10 2010
- Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> Mar 10 2010
- Henrik Huttunen <henrik.huttunen gmail.com> Mar 10 2010
- James Iry <jamesiry gmail.com> Mar 10 2010
- Bernard Helyer <b.helyer gmail.com> Mar 10 2010
- Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> Mar 10 2010
- grauzone <none example.net> Mar 10 2010
- Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> Mar 10 2010
- grauzone <none example.net> Mar 10 2010
- Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> Mar 10 2010
- grauzone <none example.net> Mar 10 2010
- Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> Mar 10 2010
- grauzone <none example.net> Mar 10 2010
- Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> Mar 10 2010
- grauzone <none example.net> Mar 10 2010
- Walter Bright <newshound1 digitalmars.com> Mar 10 2010
- grauzone <none example.net> Mar 10 2010
- Walter Bright <newshound1 digitalmars.com> Mar 10 2010
- grauzone <none example.net> Mar 11 2010
- James Iry <jamesiry gmail.com> Mar 10 2010
- Walter Bright <newshound1 digitalmars.com> Mar 10 2010
- Walter Bright <newshound1 digitalmars.com> Mar 07 2010
- bearophile <bearophileHUGS lycos.com> Mar 07 2010
- Walter Bright <newshound1 digitalmars.com> Mar 07 2010
- bearophile <bearophileHUGS lycos.com> Mar 07 2010
- BCS <none anon.com> Mar 07 2010
- grauzone <none example.net> Mar 08 2010
- Walter Bright <newshound1 digitalmars.com> Mar 08 2010
- grauzone <none example.net> Mar 08 2010
- bearophile <bearophileHUGS lycos.com> Mar 08 2010
- grauzone <none example.net> Mar 08 2010
- Walter Bright <newshound1 digitalmars.com> Mar 08 2010
- Walter Bright <newshound1 digitalmars.com> Mar 08 2010
- grauzone <none example.net> Mar 08 2010
- Walter Bright <newshound1 digitalmars.com> Mar 08 2010
- Walter Bright <newshound1 digitalmars.com> Mar 08 2010
- KennyTM~ <kennytm gmail.com> Mar 09 2010
- Michel Fortin <michel.fortin michelf.com> Mar 08 2010
- Walter Bright <newshound1 digitalmars.com> Mar 07 2010
- BCS <none anon.com> Mar 07 2010
- Walter Bright <newshound1 digitalmars.com> Mar 07 2010
- bearophile <bearophileHUGS lycos.com> Mar 07 2010
- Walter Bright <newshound1 digitalmars.com> Mar 07 2010
- BCS <none anon.com> Mar 07 2010
- Walter Bright <newshound1 digitalmars.com> Mar 07 2010
- Walter Bright <newshound1 digitalmars.com> Mar 08 2010
- BCS <none anon.com> Mar 08 2010
- Walter Bright <newshound1 digitalmars.com> Mar 08 2010
- retard <re tard.com.invalid> Mar 08 2010
- retard <re tard.com.invalid> Mar 08 2010
- "Simen kjaeraas" <simen.kjaras gmail.com> Mar 08 2010
- retard <re tard.com.invalid> Mar 07 2010
- Walter Bright <newshound1 digitalmars.com> Mar 07 2010
- "Nick Sabalausky" <a a.a> Mar 09 2010
- retard <re tard.com.invalid> Mar 07 2010
- retard <re tard.com.invalid> Mar 07 2010
- BCS <none anon.com> Mar 07 2010
- "Nick Sabalausky" <a a.a> Mar 09 2010
- retard <re tard.com.invalid> Mar 09 2010
- "Nick Sabalausky" <a a.a> Mar 09 2010
- BCS <none anon.com> Mar 09 2010
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> Mar 07 2010
- Leandro Lucarella <llucax gmail.com> Mar 07 2010
- retard <re tard.com.invalid> Mar 07 2010
- retard <re tard.com.invalid> Mar 07 2010
- "Simen kjaeraas" <simen.kjaras gmail.com> Mar 08 2010
- retard <re tard.com.invalid> Mar 08 2010
- retard <re tard.com.invalid> Mar 08 2010
- "Denis Koroskin" <2korden gmail.com> Mar 08 2010
- "Steven Schveighoffer" <schveiguy yahoo.com> Mar 08 2010
- retard <re tard.com.invalid> Mar 09 2010
"Jane Doe" <JanisD comcast.net> wrote in message news:hmsvgc$iel$1 digitalmars.com...Is D a cult?
Yes. Send us all your worldly possesions. And try the kool-aid (I'll refrain from saying that it's "to die for"...crap, too late).
Mar 05 2010
Jane Doe Wrote:Is D a cult?
Did you mean occult? http://answers.yahoo.com/question/index?qid=20080701114449AAxUTtT
Mar 06 2010
On 06.03.2010 13:55, Justin Johansson wrote:Jane Doe Wrote:Is D a cult?
Did you mean occult? http://answers.yahoo.com/question/index?qid=20080701114449AAxUTtT
The Power of Bright compels you! The Power of Bright compels you!
Mar 06 2010
Jane Doe Wrote:Is D a cult?
Compile Phobos backward to get the true message.
Mar 06 2010
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Bane wrote:Jane Doe Wrote:Is D a cult?
Compile Phobos backward to get the true message.
lol. Brilliant. - -- My enormous talent is exceeded only by my outrageous laziness. http://www.ssTk.co.uk -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iD8DBQFLkqkMT9LetA9XoXwRAgQuAKCiuJ5CT5vZfLW6UpynKtIiG5BsSwCeK/kc 87iHo7qqyx4bwWxIbJFdufI= =e9cz -----END PGP SIGNATURE-----
Mar 06 2010
On Sat, 06 Mar 2010 01:16:12 -0600, Jane Doe wrote:Is D a cult?
No but seriously ...
Mar 06 2010
Jane Doe wrote:Is D a cult?
I think the word you are looking for is "hivemind" ;)
Mar 06 2010
Hello Jane,Is D a cult?
No, not yet. Walter hasn't figured out how to brain wash people over a newsgroup yet. However I think Andrei's working on it and Don should have a patch in time for TDPL going out ;b -- ... <IXOYE><
Mar 06 2010
retard Wrote:Sun, 07 Mar 2010 05:05:03 +0000, BCS wrote:Hello Jane,Is D a cult?
newsgroup yet. However I think Andrei's working on it and Don should have a patch in time for TDPL going out ;b
FWIW, I think there is a kernel of truth in the original claim. People tend to agree evey time Walter proposes a new feature such as built-in regexps - yes, they were removed shortly afterwards. But when bearophile or some retard propose some features from functional languages that are natural extensions to existing ones, everyone hates them and tells us to go back to our ivory towers.
Blasphemy! Heretic! Joke aside, you are right from your point of view. On the other hand, I feel there is always risk for a project to became a bloated mess if it tries to satisfy needs of too many people, so some form of authority is needed to trim request here and there. Is that authority flawless? Of course not. Some good features are missing, some bad are still here, I am getting bolder each day and executables are growing bigger with each version. Other thant that, it got it pretty right so far otherwise we wouldn't be here having this chat :D
Mar 07 2010
retard wrote:Sun, 07 Mar 2010 05:05:03 +0000, BCS wrote:Hello Jane,Is D a cult?
newsgroup yet. However I think Andrei's working on it and Don should have a patch in time for TDPL going out ;b
FWIW, I think there is a kernel of truth in the original claim. People tend to agree evey time Walter proposes a new feature such as built-in regexps - yes, they were removed shortly afterwards. But when bearophile or some retard propose some features from functional languages that are natural extensions to existing ones, everyone hates them and tells us to go back to our ivory towers.
That's weird, I don't see this at all. Maybe you focus too much on one or two negative comments? I also don't understand that you think D designers have a bias against functional programming, especially since the majority of the features that have been implemented the last years are heavily influenced by that style of programming.
Mar 07 2010
retard wrote:Sun, 07 Mar 2010 14:12:14 +0100, Lutger wrote:retard wrote:Sun, 07 Mar 2010 05:05:03 +0000, BCS wrote:Hello Jane,Is D a cult?
newsgroup yet. However I think Andrei's working on it and Don should have a patch in time for TDPL going out ;b
FWIW, I think there is a kernel of truth in the original claim. People tend to agree evey time Walter proposes a new feature such as built-in regexps - yes, they were removed shortly afterwards. But when bearophile or some retard propose some features from functional languages that are natural extensions to existing ones, everyone hates them and tells us to go back to our ivory towers.
That's weird, I don't see this at all. Maybe you focus too much on one or two negative comments? I also don't understand that you think D designers have a bias against functional programming, especially since the majority of the features that have been implemented the last years are heavily influenced by that style of programming.
Uh, majority of the features? From http://www.digitalmars.com/d/2.0/ features2.html:
Let's see what features I had in mind: - Algrebraic data types - Pattern matching (extension to enum/string/integer accepting switch) - Higher kinded types - Tuples (no auto-folding, real product types) - Built-in variants (real sum types) - Currying, lazy evaluation - Fusion optimizations (e.g. list and stream fusion) - Type classes - basic control constructs are expressions, not statements (e.g. unify if- then-else and : ? into a functional if-then-else) - better syntax for lambdas [1] if immutability is considered functional
Isn't this THE cornerstone of functional programming style???[2] if type inference is considered functional
I don't see why. With 'majority of features' I meant the ones that have most impact or is spend the most effort on. Not just a count of checkboxes. A lot of those features you mention are either small or cleanup of the language. Remember that D is at heart not a functional language, so it's not surprising a lot of improvements are not of that nature. The const/immutable regime however and everything that connected to it (like referential transparency), has been the main focus of design. Furthermore, a lot of phobos is at least heavily inspired by functional programming ideas (map/reduce/curry/compose/variant, etc.). I'm not arguing with you about what feature set is good / bad / special or how it is implemented. Just saying that functional language ideas are being ignored is complete nonsense.
Mar 07 2010
retard wrote:Let's see what features I had in mind: - Algrebraic data types
std.variant covers this.- Pattern matching (extension to enum/string/integer accepting switch)
Andrei and Sean have shown how to do that nicely with existing language features.- Higher kinded types
Don't know what that is.- Tuples (no auto-folding, real product types)
Tuples can be better, I agree.- Built-in variants (real sum types)
std.variant works fine. Don't know how having them be built-in would improve things.- Currying, lazy evaluation
Already supports this.- Fusion optimizations (e.g. list and stream fusion)
Andrei demonstrated how to do this neatly with ranges.- Type classes
Don't know what this is.- basic control constructs are expressions, not statements
Perhaps, but I still think it's necessary for D do be a { } Algol-style language. Nevertheless, I've demonstrated how this can be simply done using existing features.(e.g. unify if-then-else and : ? into a functional if-then-else)
What's the difference between ?: and functional if-then-else?- better syntax for lambdas
The lambda syntax is as good as it's going to get without throwing out a *lot* of syntax compatibility.[1] if immutability is considered functional [2] if type inference is considered functional
Several of your points are not, to my mind, fundamental issues of functional programming. To me, the foundations of FP are immutability, purity, and closures, which got a lot of attention. Most of your points are already supported by D, although not quite as conveniently as in many other languages.
Mar 07 2010
In this post I am *not* asking for new features in D, I just try to give few answers :-) I think most of those things are not fit for D, they require a different language, a different compiler, different programmers, and probably a different compiler writer too :-) (I think in D for example list comphrensions fit better). The problem is that I am not an expert on such things, so what I say is not fully reliable (and another smaller problem is that I am not always sure what retard meant). If you don't understand or you don't agree with something I write here please ask. Walter Bright:- Built-in variants (real sum types)<<
std.variant works fine. Don't know how having them be built-in would improve things.<
I think retard here meant something different from D variant type. I think he meant something like the type int|float or int|float|double. The type system then knows that a variable of such type can contain only an int or a float, and nothing else. So you can think of it as a tagged union. But it's not just a C tagged union, functional languages are able to manage such int|float type very well, for example accepting in the code only operators that are allowed on both types.- Fusion optimizations (e.g. list and stream fusion)<<
Andrei demonstrated how to do this neatly with ranges.<
I think Andrei was showing something different. You can think of Fusion optimization as a compiler optimization, done by good compilers of lazy functional languages :-) It's useful to remove some useless operations, and turn a certain not effient functional algorithm into something that runs fast. You can find something here: http://stackoverflow.com/questions/578063/what-is-haskells-stream-fusion (In my opinion D language is far from being in need of this optimization.)- Algrebraic data types<<
std.variant covers this.<
I am sorry, but std.variant has nothing to do with Algrebraic data types :-) (The words retard has used come from computer science still, but it's another dialect, of the functional programmers. So even things that sound similar can be quite different things). I have shown Algrebraic data types a little on this newsgroup once in the past. This page contains some information: http://en.wikipedia.org/wiki/Algebraic_data_type- Type classes<<
Don't know what this is.<
This page gives some basic information: http://en.wikipedia.org/wiki/Type_classes While you read that, keep in mind the difference between a Nominative type system like the D one, and a structural one like the one of Haskell: http://en.wikipedia.org/wiki/Nominative_type_system- Higher kinded types<<
Don't know what that is.<
This is quickly going into a mess. There are very few languages with those, maybe only Haskell and Scala. You can find some information here, but it's not easy read: http://en.wikipedia.org/wiki/Kind_%28type_theory%29 http://www.cs.kuleuven.be/~adriaan/files/higher.pdf I'll need few more years to start to start to digest some of this stuff. Bye, bearophile
Mar 07 2010
On 03/07/2010 08:17 PM, Walter Bright wrote:What's the difference between ?: and functional if-then-else?
?: combined with some fun delegate thunks would be equivalent to functional if-then-else. like this: return x > y ? ({writeln(); return 6;})() : ({frobnicate_the_freezer; return 2;})();
Mar 07 2010
retard wrote:It's perfectly clear to me that no matter what you do, D won't become a functional language because the core runs on an imperative Turing machine. But the functional constructs can help building more readable and reliable code. That's why C# and Scala got those features..
I'll reply to your other points later, but this one bothers me. Neither C# nor Scala support pure functions or immutable data structures, which are fundamental to FP. I don't see how they can be considered as supporting functional programming. http://en.wikipedia.org/wiki/Scala_(programming_language)#Functional_programming http://www.25hoursaday.com/weblog/CommentView.aspx?guid=3D5755BF-43CF-4D47-A7EC-B60F6B536702
Mar 07 2010
retard wrote:On the other hand Scala does provide a shallow form of immutability and some immutable data structures in the standard library.
My experience with shallow const (in C++) is that it's nearly useless. Most C++ code I've seen seems to rely on an implicit assumption of transitive const, but it isn't in the documentation and of course you don't know if it is upheld or not. This is not conducive to reliable FP.I don't know if D2 provides any built-in immutable data structures. I guess just wrapping a data structure in immutable() won't suffice since there are probably some state changing functions in the mutable implementation that need to copy when dealing with immutable values.
Certainly, the D standard collection classes can improve, and they are being worked on.The good thing in Scala and C# is that they both provide nice tools for expressing functional problems without too much verbosity. When the const system in D works, I guess it solves the other part of the problem. Too bad you can't have them all without resorting to pure functional languages.
Without transitive immutability and purity, it's like putting a frock on Schwarzenegger. That's why I've been so adamant about having transitive immutability in D. I don't agree with calling a language FP without it.
Mar 07 2010
Simen kjaeraas wrote:Walter Bright <newshound1 digitalmars.com> wrote:My experience with shallow const (in C++) is that it's nearly useless. Most C++ code I've seen seems to rely on an implicit assumption of transitive const, but it isn't in the documentation and of course you don't know if it is upheld or not. This is not conducive to reliable FP.
I still remember my first reading about D const, and thinking 'What? Other const regimes aren't transitive? That's madness!'
I'm interested in what will happen with all these new languages adopting FP window dressing and concurrent programming features, but with no immutability and no purity. They're building a house on sand.
Mar 08 2010
I'm going to assume you meant "enforce" rather than "support" because both languages support immutability and purity precisely to the extent that the programmers want to use them (although, of the two, Scala's standard library has far more support). But even if you mean "enforce", you've still got a strange point of view. Common Lisp and Scheme do not enforce purity or immutability. In fact, in both languages, ALL data structures are mutable whether you want them to be or not. Yet the Scheme crowd in particular is deeply aware of the downsides of side effects. SML and OCaml do not enforce purity or immutability except in a shallow sense that unlike (most) Lisps you can write data structures which are immutable. Scala sits firmly in that same camp. For instance, like SML, the Scala standard library List type is immutable (and persistent - meaning some operations, like prepend and tail, share structure with previous versions). To insist that functional programming must be done in a language that enforces purity is to say that nobody ever did functional programming in a Lisp or ML derived language. That's historically false and many of the core concepts found in Haskell (1999) and Miranda (1985) were clearly already worked out in ML(1973) and LISP(1958). It also ignores the fact that the current Scheme, OCaml, and, yes, Scala communities work hard to create and use high performance immutable, persistent data structures. What the purely functional languages really have brought to the table is a) clean ways to separate IO using things like linear types (Clean), monads(Haskell), or effect systems(Disciple) and b) a deep awareness of the power of laziness that can be found, to some extent, in the impure functional languages but which is pervasive in the pure lazy ones. Also, GHC Haskell, the current reigning king of purity includes "unsafePerformIO" precisely because there is such a thing as too much purity. Besides doing traditional IO it allows the programmer to mutate shared variables and do other, nasty, imperative things. Walter Bright Wrote:retard wrote:It's perfectly clear to me that no matter what you do, D won't become a functional language because the core runs on an imperative Turing machine. But the functional constructs can help building more readable and reliable code. That's why C# and Scala got those features..
I'll reply to your other points later, but this one bothers me. Neither C# nor Scala support pure functions or immutable data structures, which are fundamental to FP. I don't see how they can be considered as supporting functional programming. http://en.wikipedia.org/wiki/Scala_(programming_language)#Functional_programming http://www.25hoursaday.com/weblog/CommentView.aspx?guid=3D5755BF-43CF-4D47-A7EC-B60F6B536702
Mar 10 2010
On 03/10/2010 10:09 AM, James Iry wrote:I'm going to assume you meant "enforce" rather than "support" because both languages support immutability and purity precisely to the extent that the programmers want to use them (although, of the two, Scala's standard library has far more support). But even if you mean "enforce", you've still got a strange point of view.
Functional programming means (a) first-order functions, and (b) immutability. There are no ifs and buts about it. Every text on functional programming says as much. Even Wikipedia :o), but I'd recommend this classic: https://docs.google.com/viewer?url=http://www.cs.chalmers.se/~rjmh/Papers/whyfp.pdf The rest (lambdas, extensive use of recursion, pattern matching, let and letrec, monads, system(at)ic laziness) is aftermath, i.e. mechanisms that make it convenient to program given (a) and (b). There are no ifs and buts about that either. Giving FP lip service by adopting FP's window dressing and syntactic sugar while at the same time not giving due consideration to FP's two fundamental tenets is, in my opinion, an ungainly move in the long term. Andrei
Mar 10 2010
Andrei Alexandrescu Wrote:Functional programming means (a) first-order functions, and (b) immutability. There are no ifs and buts about it.
Really? Maybe you meant higher-order functions or functions as first-class citizens?
Mar 10 2010
On 03/10/2010 11:48 AM, Henrik Huttunen wrote:Andrei Alexandrescu Wrote:Functional programming means (a) first-order functions, and (b) immutability. There are no ifs and buts about it.
Really? Maybe you meant higher-order functions or functions as first-class citizens?
Damn. "First class". Andrei
Mar 10 2010
Andrei Alexandrescu Wrote: I don't disagree with you (except that you probably meant "first class" rather than "first order"). But that wasn't the question. The question was "does a language have to enforce purity in order to be a functional language" and the answer is that historically that has not been the case. The Lisp family (especially Scheme) and the ML family both have a rich tradition of purely functional programming without ever having the purity enforced. They did not "adopt the functional window dressing"; they invented it.Functional programming means (a) first-order functions, and (b) immutability. There are no ifs and buts about it. Every text on functional programming says as much. Even Wikipedia :o), but I'd recommend this classic: https://docs.google.com/viewer?url=http://www.cs.chalmers.se/~rjmh/Papers/whyfp.pdf The rest (lambdas, extensive use of recursion, pattern matching, let and letrec, monads, system(at)ic laziness) is aftermath, i.e. mechanisms that make it convenient to program given (a) and (b). There are no ifs and buts about that either. Giving FP lip service by adopting FP's window dressing and syntactic sugar while at the same time not giving due consideration to FP's two fundamental tenets is, in my opinion, an ungainly move in the long term. Andrei
Mar 10 2010
On 11/03/10 09:42, James Iry wrote:But that wasn't the question. The question was "does a language have to enforce purity in order to be a functional language" and the answer is that historically that has not been the case.
I know nothing about FP, but isn't the statement 'does a language have to enforce $(PRECONDITION_X) in order to be a $(PARADIGM_LANGUAGE)' a fairly broad one? Can't most languages be programmed in such a way as to fulfill most paradigms through strict coding practices? I guess the question then becomes a question of degrees (Logical Programming in x86 assembly?), and as I said, I know nothing about FP, so I will deftly run away. Brave, brave Sir Robin...
Mar 10 2010
On 03/10/2010 02:42 PM, James Iry wrote:Andrei Alexandrescu Wrote: I don't disagree with you (except that you probably meant "first class" rather than "first order"). But that wasn't the question. The question was "does a language have to enforce purity in order to be a functional language" and the answer is that historically that has not been the case. The Lisp family (especially Scheme) and the ML family both have a rich tradition of purely functional programming without ever having the purity enforced. They did not "adopt the functional window dressing"; they invented it.
Mutation has always been seen as an awkward concession to efficiency by functional languages, and limited to the maximum extent possible. LISP has commonly used a pure subset (see e.g. http://www-formal.stanford.edu/jmc/history/lisp/node3.html) for proving essentially everything there is to be proven regarding functional programming. There's one final nail in the coffin. In wake of concurrency, de jure immutability becomes a necessity, not a useful and desirable de facto convention. Adopting the window dressing but not the essence of FP by a concurrent language evokes to me a scene in the Marx Brothers: an otherwise impeccably-dressed gentleman who forgot to put his pants on. Andrei
Mar 10 2010
Andrei Alexandrescu wrote:There's one final nail in the coffin. In wake of concurrency, de jure immutability becomes a necessity, not a useful and desirable de facto convention. Adopting the window dressing but not the essence of FP by a concurrent language evokes to me a scene in the Marx Brothers: an otherwise impeccably-dressed gentleman who forgot to put his pants on.
Language support is not strictly necessary to get the same effects as immutable types, as far as multithreading is concerned: small data can be copied, and large data can be made read-only by OS syscalls. This just had to be in the message passing library. (As a bonus, it isn't possible to subvert these mechanisms just by casting.)
Mar 10 2010
On 03/10/2010 05:01 PM, grauzone wrote:Andrei Alexandrescu wrote:There's one final nail in the coffin. In wake of concurrency, de jure immutability becomes a necessity, not a useful and desirable de facto convention. Adopting the window dressing but not the essence of FP by a concurrent language evokes to me a scene in the Marx Brothers: an otherwise impeccably-dressed gentleman who forgot to put his pants on.
Language support is not strictly necessary to get the same effects as immutable types, as far as multithreading is concerned: small data can be copied, and large data can be made read-only by OS syscalls. This just had to be in the message passing library. (As a bonus, it isn't possible to subvert these mechanisms just by casting.)
That'll never work. The OS granularity is 4KB increments. Andrei
Mar 10 2010
Andrei Alexandrescu wrote:On 03/10/2010 05:01 PM, grauzone wrote:Andrei Alexandrescu wrote:There's one final nail in the coffin. In wake of concurrency, de jure immutability becomes a necessity, not a useful and desirable de facto convention. Adopting the window dressing but not the essence of FP by a concurrent language evokes to me a scene in the Marx Brothers: an otherwise impeccably-dressed gentleman who forgot to put his pants on.
Language support is not strictly necessary to get the same effects as immutable types, as far as multithreading is concerned: small data can be copied, and large data can be made read-only by OS syscalls. This just had to be in the message passing library. (As a bonus, it isn't possible to subvert these mechanisms just by casting.)
That'll never work. The OS granularity is 4KB increments.
Data this small you would simply copy. Because it's so small, copying won't have negative performance impact. The OS approach can be used for large data (at least in the order of hundreds of KB) and immutable parts of the data segment.Andrei
Mar 10 2010
On 03/10/2010 06:06 PM, grauzone wrote:Andrei Alexandrescu wrote:On 03/10/2010 05:01 PM, grauzone wrote:Andrei Alexandrescu wrote:There's one final nail in the coffin. In wake of concurrency, de jure immutability becomes a necessity, not a useful and desirable de facto convention. Adopting the window dressing but not the essence of FP by a concurrent language evokes to me a scene in the Marx Brothers: an otherwise impeccably-dressed gentleman who forgot to put his pants on.
Language support is not strictly necessary to get the same effects as immutable types, as far as multithreading is concerned: small data can be copied, and large data can be made read-only by OS syscalls. This just had to be in the message passing library. (As a bonus, it isn't possible to subvert these mechanisms just by casting.)
That'll never work. The OS granularity is 4KB increments.
Data this small you would simply copy. Because it's so small, copying won't have negative performance impact. The OS approach can be used for large data (at least in the order of hundreds of KB) and immutable parts of the data segment.
Trust me, that will never work anywhere close to satisfactory. It's even useless to talk about it. Andrei
Mar 10 2010
Andrei Alexandrescu wrote:On 03/10/2010 06:06 PM, grauzone wrote:Andrei Alexandrescu wrote:On 03/10/2010 05:01 PM, grauzone wrote:Andrei Alexandrescu wrote:There's one final nail in the coffin. In wake of concurrency, de jure immutability becomes a necessity, not a useful and desirable de facto convention. Adopting the window dressing but not the essence of FP by a concurrent language evokes to me a scene in the Marx Brothers: an otherwise impeccably-dressed gentleman who forgot to put his pants on.
Language support is not strictly necessary to get the same effects as immutable types, as far as multithreading is concerned: small data can be copied, and large data can be made read-only by OS syscalls. This just had to be in the message passing library. (As a bonus, it isn't possible to subvert these mechanisms just by casting.)
That'll never work. The OS granularity is 4KB increments.
Data this small you would simply copy. Because it's so small, copying won't have negative performance impact. The OS approach can be used for large data (at least in the order of hundreds of KB) and immutable parts of the data segment.
Trust me, that will never work anywhere close to satisfactory. It's even useless to talk about it.
Just saying "it won't work" is a bit empty. Do you happen to have any arguments?Andrei
Mar 10 2010
On 03/10/2010 06:47 PM, grauzone wrote:Andrei Alexandrescu wrote:On 03/10/2010 06:06 PM, grauzone wrote:Andrei Alexandrescu wrote:On 03/10/2010 05:01 PM, grauzone wrote:Andrei Alexandrescu wrote:There's one final nail in the coffin. In wake of concurrency, de jure immutability becomes a necessity, not a useful and desirable de facto convention. Adopting the window dressing but not the essence of FP by a concurrent language evokes to me a scene in the Marx Brothers: an otherwise impeccably-dressed gentleman who forgot to put his pants on.
Language support is not strictly necessary to get the same effects as immutable types, as far as multithreading is concerned: small data can be copied, and large data can be made read-only by OS syscalls. This just had to be in the message passing library. (As a bonus, it isn't possible to subvert these mechanisms just by casting.)
That'll never work. The OS granularity is 4KB increments.
Data this small you would simply copy. Because it's so small, copying won't have negative performance impact. The OS approach can be used for large data (at least in the order of hundreds of KB) and immutable parts of the data segment.
Trust me, that will never work anywhere close to satisfactory. It's even useless to talk about it.
Just saying "it won't work" is a bit empty. Do you happen to have any arguments?
I'd need to build a fair amount of background, which I don't have time for. Andrei
Mar 10 2010
Andrei Alexandrescu wrote:On 03/10/2010 06:47 PM, grauzone wrote:Andrei Alexandrescu wrote:On 03/10/2010 06:06 PM, grauzone wrote:Andrei Alexandrescu wrote:On 03/10/2010 05:01 PM, grauzone wrote:Andrei Alexandrescu wrote:There's one final nail in the coffin. In wake of concurrency, de jure immutability becomes a necessity, not a useful and desirable de facto convention. Adopting the window dressing but not the essence of FP by a concurrent language evokes to me a scene in the Marx Brothers: an otherwise impeccably-dressed gentleman who forgot to put his pants on.
Language support is not strictly necessary to get the same effects as immutable types, as far as multithreading is concerned: small data can be copied, and large data can be made read-only by OS syscalls. This just had to be in the message passing library. (As a bonus, it isn't possible to subvert these mechanisms just by casting.)
That'll never work. The OS granularity is 4KB increments.
Data this small you would simply copy. Because it's so small, copying won't have negative performance impact. The OS approach can be used for large data (at least in the order of hundreds of KB) and immutable parts of the data segment.
Trust me, that will never work anywhere close to satisfactory. It's even useless to talk about it.
Just saying "it won't work" is a bit empty. Do you happen to have any arguments?
I'd need to build a fair amount of background, which I don't have time for.
I don't think you'd need large amounts of "background" for a short and precise answer. It's not rocket science either. Though you could simply say "I don't want to answer now".Andrei
Mar 10 2010
On 03/10/2010 07:07 PM, grauzone wrote:Andrei Alexandrescu wrote:On 03/10/2010 06:47 PM, grauzone wrote:Andrei Alexandrescu wrote:On 03/10/2010 06:06 PM, grauzone wrote:Andrei Alexandrescu wrote:On 03/10/2010 05:01 PM, grauzone wrote:Andrei Alexandrescu wrote:There's one final nail in the coffin. In wake of concurrency, de jure immutability becomes a necessity, not a useful and desirable de facto convention. Adopting the window dressing but not the essence of FP by a concurrent language evokes to me a scene in the Marx Brothers: an otherwise impeccably-dressed gentleman who forgot to put his pants on.
Language support is not strictly necessary to get the same effects as immutable types, as far as multithreading is concerned: small data can be copied, and large data can be made read-only by OS syscalls. This just had to be in the message passing library. (As a bonus, it isn't possible to subvert these mechanisms just by casting.)
That'll never work. The OS granularity is 4KB increments.
Data this small you would simply copy. Because it's so small, copying won't have negative performance impact. The OS approach can be used for large data (at least in the order of hundreds of KB) and immutable parts of the data segment.
Trust me, that will never work anywhere close to satisfactory. It's even useless to talk about it.
Just saying "it won't work" is a bit empty. Do you happen to have any arguments?
I'd need to build a fair amount of background, which I don't have time for.
I don't think you'd need large amounts of "background" for a short and precise answer.
"That does not work." Andrei
Mar 10 2010
Andrei Alexandrescu wrote:On 03/10/2010 07:07 PM, grauzone wrote:Andrei Alexandrescu wrote:On 03/10/2010 06:47 PM, grauzone wrote:Andrei Alexandrescu wrote:On 03/10/2010 06:06 PM, grauzone wrote:Andrei Alexandrescu wrote:On 03/10/2010 05:01 PM, grauzone wrote:Andrei Alexandrescu wrote:There's one final nail in the coffin. In wake of concurrency, de jure immutability becomes a necessity, not a useful and desirable de facto convention. Adopting the window dressing but not the essence of FP by a concurrent language evokes to me a scene in the Marx Brothers: an otherwise impeccably-dressed gentleman who forgot to put his pants on.
Language support is not strictly necessary to get the same effects as immutable types, as far as multithreading is concerned: small data can be copied, and large data can be made read-only by OS syscalls. This just had to be in the message passing library. (As a bonus, it isn't possible to subvert these mechanisms just by casting.)
That'll never work. The OS granularity is 4KB increments.
Data this small you would simply copy. Because it's so small, copying won't have negative performance impact. The OS approach can be used for large data (at least in the order of hundreds of KB) and immutable parts of the data segment.
Trust me, that will never work anywhere close to satisfactory. It's even useless to talk about it.
Just saying "it won't work" is a bit empty. Do you happen to have any arguments?
I'd need to build a fair amount of background, which I don't have time for.
I don't think you'd need large amounts of "background" for a short and precise answer.
"That does not work."
But it does!Andrei
Mar 10 2010
grauzone wrote:Data this small you would simply copy. Because it's so small, copying won't have negative performance impact. The OS approach can be used for large data (at least in the order of hundreds of KB) and immutable parts of the data segment.
You'd also have to transitively copy everything referenced.
Mar 10 2010
Walter Bright wrote:grauzone wrote:Data this small you would simply copy. Because it's so small, copying won't have negative performance impact. The OS approach can be used for large data (at least in the order of hundreds of KB) and immutable parts of the data segment.
You'd also have to transitively copy everything referenced.
If that becomes a problem depends entirely from how the message passing API (or whatever) is used*. And the only common case where this works really elegantly are strings. (But most strings are short and could be copied effortlessly.) On the contrary, frequently allocating immutable data on a shared heap just to transfer it to another thread isn't going to be very efficient either. You won't be able to go with a shared GC forever, because it SO doesn't scale with multiprocessing. * This stuff probably depends a lot on actual use cases. Did you or Andrei envision anything in this direction? I figure you thought about this much more than e.g. me, but I never hear any concrete things.
Mar 10 2010
grauzone wrote:Walter Bright wrote:grauzone wrote:Data this small you would simply copy. Because it's so small, copying won't have negative performance impact. The OS approach can be used for large data (at least in the order of hundreds of KB) and immutable parts of the data segment.
You'd also have to transitively copy everything referenced.
If that becomes a problem depends entirely from how the message passing API (or whatever) is used*.
If there's anything I've learned about language design, it's that if there is a capability, it will be used, and if there's a major problem with it, that will generate major complaints. The fact is, people *do* have major problems with concurrent programming. Sharing of mutable state is a large generator of these problems, and I don't think we can wish it away or blame the programmer. What transitive immutability offers is a guarantee. As programs become ever larger and more complicated, relying on individual programmer diligence and uncheckable conventions is less and less acceptable. For example, we're at the stage now where mainstream languages offer guarantees against buffer overflows. This is a huge win - just witness the $$$$$ the C shops spend on Coverity to desperately try and squeeze them out of their code.
Mar 10 2010
Walter Bright wrote:The fact is, people *do* have major problems with concurrent programming. Sharing of mutable state is a large generator of these problems, and I don't think we can wish it away or blame the programmer.
I didn't advocate sharing of mutable state.
Mar 11 2010
The Lisp and Scheme LANGUAGES don't limit mutability, though. In Scheme you can literally mutate any cons cell, for instance. It's the communities that have limited the mutation in their programs in part because the language makes it easy to do so. In ML you can define any data structure to be based on mutable Refs, yet SMLers are especially keen on maintaining as much purity as they can, and OCamlers are mostly so (not entirely though, OCamlers frequently care more about efficiency than their SML brethren). The article you link only talks about LISP up to 1.5 or so. It doesn't cover Common Lisp, which is the 800 pound gorilla of the Lisp family. I bring it up because a huge amount of Common Lisp code is deeply imperative: for some reason CLispers are less interested in the value of purity than Schemer's are, even thought their language is just about as suitable (ignoring the fact that the CL spec doesn't require tail call optmization since most CL implementations support it). You may be right that it's concerns about efficiency, but I'm not entirely sure that's true since even at the small scale CLers tend to use loops where Schemers use (just as efficient) tail call recursion (yes, CL doesn't mandate TCO, but all the major implementations that I know of support it). Look, I'm not arguing that uncontrolled side effects are "good." What I am arguing is very simple: the definition of functional language, as applied to the vast majority of functional programming languages, does not imply any form of proof of purity. Redefining it that way is just retronyming with no good purpose when there's already a perfectly useful phrase, "purely functional programming language," to cover the Mirandas, Haskells, Cleans, Agdas, and Epigrams of the world. As for your comment about concurrency, it's a funny image, but it's false, or at least overstated. Erlang, for instance, does not put limits on effects except in the narrow sense that mutation is more awkward to express than in typical imperative languages. Some people think that Erlang does not permit the sharing of mutable state, but that's not true at all. Erlang prevents the sharing of direct access to memory, but actors are (or at least can be) stateful and can be shared concurrently, and you can get exactly the same kinds of race conditions you get in more traditional "shared state" concurrency. The difference in the Erlang model and locks/variables model is really more a matter of granularity and the programmers thought process. I talk about the state model in Erlang here (http://james-iry.blogspot.com/2009/04/erlang-style-actors-are-all-about.html). The article even ends with an implementation of sharable mutable "variables" with get and set operations, and I follow up in another article with an implementation of a mutex lock. If Erlang did not permit sharing of mutable entities then it would be too limited to be useful - concurrency (as opposed to simple parallelism) is a side effect. There's a reason Haskell pushes all of its concurrency primitives (forkIO, MVars, STM commits) into the IO Monad while the less pernicious data-parallel extensions don't require effect tracking. Now, again, limiting the scope of impurity and mutation in a concurrent setting is probably more win than not. But that does not mean we need to change the definitions of "concurrent language" or "functional programming language" to preclude Erlang just because it has no such limitations. Andrei Alexandrescu Wrote:On 03/10/2010 02:42 PM, James Iry wrote:Andrei Alexandrescu Wrote: I don't disagree with you (except that you probably meant "first class" rather than "first order"). But that wasn't the question. The question was "does a language have to enforce purity in order to be a functional language" and the answer is that historically that has not been the case. The Lisp family (especially Scheme) and the ML family both have a rich tradition of purely functional programming without ever having the purity enforced. They did not "adopt the functional window dressing"; they invented it.
Mutation has always been seen as an awkward concession to efficiency by functional languages, and limited to the maximum extent possible. LISP has commonly used a pure subset (see e.g. http://www-formal.stanford.edu/jmc/history/lisp/node3.html) for proving essentially everything there is to be proven regarding functional programming. There's one final nail in the coffin. In wake of concurrency, de jure immutability becomes a necessity, not a useful and desirable de facto convention. Adopting the window dressing but not the essence of FP by a concurrent language evokes to me a scene in the Marx Brothers: an otherwise impeccably-dressed gentleman who forgot to put his pants on. Andrei
Mar 10 2010
James Iry wrote:I'm going to assume you meant "enforce" rather than "support" because both languages support immutability and purity precisely to the extent that the programmers want to use them (although, of the two, Scala's standard library has far more support).
So does C. The problem is, without compiler support, you have a very difficult time telling by visual inspection if code is functional or not. It's like turning off type checking in your C compiler. It still works, but it's really bug prone.
Mar 10 2010
Leandro Lucarella wrote:Walter Bright, el 7 de marzo a las 11:17 me escribiste:- Tuples (no auto-folding, real product types)
Is nice to see that at least now you recognize that tuples can use some improvement.
There are significant technical problems with having functions return tuples. The problem is that alignment for arguments passed as parameters is fundamentally different from that for struct fields. Having tuple returns, tuples as fields, and tuples as function arguments all conflict with each other over this.
Mar 07 2010
Walter Bright:There are significant technical problems with having functions return tuples.<
A possibly stupid question: isn't it enough to return a custom struct? D Tuples have another problem, that they don't nest, as Perl arrays. Can this be fixed? Bye, bearophile
Mar 07 2010
bearophile wrote:Walter Bright:There are significant technical problems with having functions return tuples.<
A possibly stupid question: isn't it enough to return a custom struct?
No, because of the alignment mismatches with other uses of tuples.
Mar 07 2010
Walter Bright Wrote:No, because of the alignment mismatches with other uses of tuples.
And I guess all the other uses of tuples can't be changed to this one? :-) Bye, a hopeless bearophile
Mar 07 2010
Hello Walter,bearophile wrote:Walter Bright:There are significant technical problems with having functions return tuples.<
struct?
What about passing an array of return location pointers as a hidden arg? That would allow the called function to do the assignment. -- ... <IXOYE><
Mar 07 2010
Walter Bright wrote:bearophile wrote:Walter Bright:There are significant technical problems with having functions return tuples.<
A possibly stupid question: isn't it enough to return a custom struct?
No, because of the alignment mismatches with other uses of tuples.
I don't understand, what does alignment have to do with such a high level construct?
Mar 08 2010
grauzone wrote:Walter Bright wrote:bearophile wrote:Walter Bright:There are significant technical problems with having functions return tuples.<
A possibly stupid question: isn't it enough to return a custom struct?
No, because of the alignment mismatches with other uses of tuples.
I don't understand, what does alignment have to do with such a high level construct?
You can use a tuple to populate a struct with fields, and it's interchangeable with manually populating the fields. You can also use a tuple to pass args to a function, and it's interchangeable with manually listing the args. But if you populate a struct with a tuple, then pass the struct as an arg, it is *not* interchangeable with manually listing the args, as the alignment is different.
Mar 08 2010
Walter Bright wrote:grauzone wrote:Walter Bright wrote:bearophile wrote:Walter Bright:There are significant technical problems with having functions return tuples.<
A possibly stupid question: isn't it enough to return a custom struct?
No, because of the alignment mismatches with other uses of tuples.
I don't understand, what does alignment have to do with such a high level construct?
You can use a tuple to populate a struct with fields, and it's interchangeable with manually populating the fields. You can also use a tuple to pass args to a function, and it's interchangeable with manually listing the args. But if you populate a struct with a tuple, then pass the struct as an arg, it is *not* interchangeable with manually listing the args, as the alignment is different.
Again, I can't understand. Does the compiler rely that tuples have the same byte layout as structs or function arguments? I thought the compiler could just copy all fields. And the backend can already return multiple values, since it can return structs and static arrays. That aside, I'm also glad that you acknowledge that current tuples are not perfect and need improvement. It's probably already too late to fix them, but you could always introduce a second, proper tuple type.
Mar 08 2010
grauzone:That aside, I'm also glad that you acknowledge that current tuples are not perfect and need improvement.
I agree.It's probably already too late to fix them,<
It isn't.but you could always introduce a second, proper tuple type.<
NO. Not even think about that. Two kinds of tuples in a language is beyond ugly. Bye, bearophile
Mar 08 2010
bearophile wrote:grauzone:That aside, I'm also glad that you acknowledge that current tuples are not perfect and need improvement.
I agree.It's probably already too late to fix them,<
It isn't.
D2 is pretty much finalized now. The discussion (i.e. bikeshedding) alone to determine how tuples are done right would take much longer than this.but you could always introduce a second, proper tuple type.<
NO. Not even think about that. Two kinds of tuples in a language is beyond ugly.
The older kind of tuples would be deprecated. In 10 or 20 years, they could be removed from D completely. It is only needed for compatibility with older code and because it is in TDPL (which apparently is considered the specification of D2). In case TDPL has no dependencies on the "wrong" aspects of the current tuples, then this historic accident could be avoided.Bye, bearophile
Mar 08 2010
Steven Schveighoffer wrote:That is, as long as it doesn't conflict with what the book says, it can be changed. This is why a complete documentation of phobos is not in the book (parts are referenced, and those parts must remain frozen).
That's only a small part of the reason why. The main reason is because the book is huge. To do the standard library justice, it needs to be its own full size book.
Mar 08 2010
grauzone wrote:Again, I can't understand. Does the compiler rely that tuples have the same byte layout as structs or function arguments? I thought the compiler could just copy all fields. And the backend can already return multiple values, since it can return structs and static arrays.
A tuple and a struct composed of the same tuple should be interchangeable. This doesn't work, because the alignment is different for different circumstances.
Mar 08 2010
Walter Bright wrote:grauzone wrote:Again, I can't understand. Does the compiler rely that tuples have the same byte layout as structs or function arguments? I thought the compiler could just copy all fields. And the backend can already return multiple values, since it can return structs and static arrays.
A tuple and a struct composed of the same tuple should be interchangeable. This doesn't work, because the alignment is different for different circumstances.
Sorry for being dense, but again: what does alignment have to do with this? This works flawlessly, although there are different alignments involved: import std.stdio; struct A { align(1): short a; int b; } struct B { short a; int b; } void main() { A x = A(1, 2); B y; y.tupleof = x.tupleof; writefln("%s", y); //printf B(1, 2) writefln("%s %s", A.b.offsetof, B.b.offsetof); //prints 2 4 } You can assign the tuple from type A to B, even though the fields have different alignments. Obviously, the actual tuple type has to be the same.
Mar 08 2010
grauzone wrote:Sorry for being dense, but again: what does alignment have to do with this?
alias TypeTuple!(char, int) TT; These declarations must be IDENTICAL: void foo(TT); void foo(char, int); struct S { TT t; } struct S { char t1; int t2; } This means that if you have an aggregate that is a tuple (and tuples are, of course, aggregates) you have an aggregate that needs one alignment in one context, and another alignment in another. It doesn't work.
Mar 08 2010
retard wrote:This doesn't work, because the alignment is different for different circumstances.
Where does this requirement come from?
The natural and efficient way to align function parameters on the stack is different from aligning them for struct fields.Is there some existing work on some other language that tells one to implement it this way?
Yes, C.
Mar 08 2010
On Mar 9, 10 04:16, Walter Bright wrote:retard wrote:This doesn't work, because the alignment is different for different circumstances.
Where does this requirement come from?
The natural and efficient way to align function parameters on the stack is different from aligning them for struct fields.Is there some existing work on some other language that tells one to implement it this way?
Yes, C.
Since when did C has tuples?
Mar 09 2010
On 2010-03-08 06:37:55 -0500, Walter Bright <newshound1 digitalmars.com> said:grauzone wrote:I don't understand, what does alignment have to do with such a high level construct?
You can use a tuple to populate a struct with fields, and it's interchangeable with manually populating the fields. You can also use a tuple to pass args to a function, and it's interchangeable with manually listing the args. But if you populate a struct with a tuple, then pass the struct as an arg, it is *not* interchangeable with manually listing the args, as the alignment is different.
I think a better way to explain it is that a struct having an align(x) instruction will have different alignment than a struct with no explicit alignment, so you can't easily pass the tuple without creating a different copy with a standard alignment. For instance: struct CustomAligned { align(2): byte a; short b; } struct DefaultAligned { byte a; short b; } tuple(byte, short) foo(); CustomAligned a; a.tupleof = foo(); // how does this work under the hood? DefaultAligned b; b.tupleof = foo(); // how does this work under the hood? I think a nice ABI for this would be to pass small tuples like the one above in registers. Bigger tuples would be returned the same way as a struct having default alignment. If you're copying the tuple to a struct with non-default alignment, like in the example above, then it's the caller's responsibility to allocate temporary space on the stack and move the values as needed afterward. This would make the non-default alignment case slower, but using non-default alignment is already bound to be slower for many things. Another option is to pass a hidden pointer to each member as BCS suggested. Though I suspect this would be slower when assigning to default-aligned structs. It's not an impossible problem, but indeed it's not as simple as returning a struct. Is there some other issues I missed? -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Mar 08 2010
retard wrote:Sun, 07 Mar 2010 11:17:46 -0800, Walter Bright wrote:retard wrote:- Pattern matching (extension to enum/string/integer accepting switch)
features.
Really? I'd really like to see how this is done.
foo( v, (int i) { writeln("I saw an int ", i); }, (string s) { writeln("I saw a string ", s); ), (Variant any) { writeln("I saw the default case ", any); } ); foo is a variadic template which takes its first argument, v, and attempts to match it with each delegate in turn. The first one that matches is executed. The matching is all done at compile time, of course, and the delegate can be inlined.
Mar 07 2010
Hello Walter,retard wrote:Sun, 07 Mar 2010 11:17:46 -0800, Walter Bright wrote:retard wrote:- Pattern matching (extension to enum/string/integer accepting switch)
language features.
attempts to match it with each delegate in turn. The first one that matches is executed. The matching is all done at compile time, of course, and the delegate can be inlined.
I think (from context in other strands) that the OP was referring to value, not type, pattern matching.
... <IXOYE><
Mar 07 2010
BCS wrote:I think (from context in other strands) that the OP was referring to value, not type, pattern matching.
Value pattern matching is just a regular switch statement.
Mar 07 2010
retard:So what types does the regular switch accept in D 2 ?
It accepts all integral values, including all chars and true enums. It accepts strings but not arrays. It doesn't accept floating point values, complex numbers (that are FP), structs, objects and associative arrays. Eventually support for arrays and structs too can be added, someone in the D Wish list has asked for those two things, but so far I haven't found a need for this. If D adds tagged structs, then switch can read their tag. Time ago I have thought about an opSwitch operator for structs/classes, that gets called by switch, but I haven had not enough need for something like this so far. So I have never asked for it. Bye, bearophile
Mar 07 2010
retard wrote:Sun, 07 Mar 2010 15:59:37 -0800, Walter Bright wrote:BCS wrote:I think (from context in other strands) that the OP was referring to value, not type, pattern matching.
So what types does the regular switch accept in D 2 ?
I already posted the way to do type pattern matching.
Mar 07 2010
Hello Walter,retard wrote:Sun, 07 Mar 2010 15:59:37 -0800, Walter Bright wrote:BCS wrote:I think (from context in other strands) that the OP was referring to value, not type, pattern matching.
I think what retard was asking was what types are legal as the argument for a switch? IIRC the list is: all the arithmetic types and the string types. The value pattern matching that is being asked for would allow just about anything that has a compile time literal syntax: void fn(int[] ar) { switch(ar) { case [1,2,3]: ... break; case [1,2,4]: ... break; case [1,3,2]: ... break; } } -- ... <IXOYE><
Mar 07 2010
BCS wrote:I think what retard was asking was what types are legal as the argument for a switch? IIRC the list is: all the arithmetic types and the string types. The value pattern matching that is being asked for would allow just about anything that has a compile time literal syntax: void fn(int[] ar) { switch(ar) { case [1,2,3]: ... break; case [1,2,4]: ... break; case [1,3,2]: ... break; } }
I've thought more than once about adding that, but it just seems pointless. I've never run into a use case for it. If you do run into one, if (ar == [1,2,3]) ... else if (ar == [1,2,4]) ... else if (ar == [1,3,2]) ... will work just fine.
Mar 07 2010
retard wrote:I've thought more than once about adding that, but it just seems pointless. I've never run into a use case for it. If you do run into one, if (ar == [1,2,3]) ... else if (ar == [1,2,4]) ... else if (ar == [1,3,2]) ... will work just fine.
The same can be said about matching integer values:if (ar == 1) ... else if (ar == 2) ... else if (ar == 3) ...
I don't agree, because switching on integer values is commonplace, and switching on array literals pretty much never happens. (Note: switching on floating point values is worse than useless, as floating point computations rarely produce exact results, and supporting such a capability will give a false sense that it should work.)I guess the point is just to unify many kinds of cases. class Foo class Bar : Foo { void doBarMethod() {} } class Bar2 : Foo { void doBar2Method() {} } if (cast(Bar)foo) (cast(Bar)foo).doBarMethod(); else if (cast(Bar2)foo) (cast(Bar2)foo).doBar2Method(); else writefln("Oh no!")
I have to say, if you find code written that way, you're doing OOP wrong.foo match { case b: Bar => b.doBarMethod case b: Bar2 => b.doBar2Method case _ => println("Oh no!") } (1, (1,2)) match { case (1, (1, _)) => println("nice tuple") case _ => } def main(args: Array[Byte]) = args(0) match { case "-help" => println("Usage: ...") case "-moo" => println("moo") }
D already supports string switches.
Mar 08 2010
Hello Walter,(Note: switching on floating point values is worse than useless, as floating point computations rarely produce exact results, and supporting such a capability will give a false sense that it should work.)
What about allowing switch on FP but only allowing CaseRangeStatements? -- ... <IXOYE><
Mar 08 2010
BCS wrote:What about allowing switch on FP but only allowing CaseRangeStatements?
Is there really a compelling use case for that? I really think we need to focus on what is needed to be done, not what can be done. Otherwise we wind up with a huge boatload of features yet have an unuseful language.
Mar 08 2010
Sun, 07 Mar 2010 22:05:19 -0800, Walter Bright wrote:BCS wrote:I think what retard was asking was what types are legal as the argument for a switch? IIRC the list is: all the arithmetic types and the string types. The value pattern matching that is being asked for would allow just about anything that has a compile time literal syntax: void fn(int[] ar) { switch(ar) { case [1,2,3]: ... break; case [1,2,4]: ... break; case [1,3,2]: ... break; } }
I've thought more than once about adding that, but it just seems pointless. I've never run into a use case for it. If you do run into one, if (ar == [1,2,3]) ... else if (ar == [1,2,4]) ... else if (ar == [1,3,2]) ... will work just fine.
The same can be said about matching integer values:if (ar == 1) ... else if (ar == 2) ... else if (ar == 3) ...
I guess the point is just to unify many kinds of cases. class Foo class Bar : Foo { void doBarMethod() {} } class Bar2 : Foo { void doBar2Method() {} } if (cast(Bar)foo) (cast(Bar)foo).doBarMethod(); else if (cast(Bar2)foo) (cast(Bar2)foo).doBar2Method(); else writefln("Oh no!") foo match { case b: Bar => b.doBarMethod case b: Bar2 => b.doBar2Method case _ => println("Oh no!") } (1, (1,2)) match { case (1, (1, _)) => println("nice tuple") case _ => } def main(args: Array[Byte]) = args(0) match { case "-help" => println("Usage: ...") case "-moo" => println("moo") }
Mar 08 2010
Mon, 08 Mar 2010 03:35:56 -0800, Walter Bright wrote:retard wrote:I've thought more than once about adding that, but it just seems pointless. I've never run into a use case for it. If you do run into one, if (ar == [1,2,3]) ... else if (ar == [1,2,4]) ... else if (ar == [1,3,2]) ... will work just fine.
The same can be said about matching integer values:if (ar == 1) ... else if (ar == 2) ... else if (ar == 3) ...
I don't agree, because switching on integer values is commonplace, and switching on array literals pretty much never happens. (Note: switching on floating point values is worse than useless, as floating point computations rarely produce exact results, and supporting such a capability will give a false sense that it should work.)I guess the point is just to unify many kinds of cases. class Foo class Bar : Foo { void doBarMethod() {} } class Bar2 : Foo { void doBar2Method() {} } if (cast(Bar)foo) (cast(Bar)foo).doBarMethod(); else if (cast(Bar2)foo) (cast(Bar2)foo).doBar2Method(); else writefln("Oh no!")
I have to say, if you find code written that way, you're doing OOP wrong.
The "correct" solution, multimethods or the visitor pattern, is sometimes very expensive. They become very verbose when compared to simple pattern matching:foo match { case b: Bar => b.doBarMethod case b: Bar2 => b.doBar2Method case _ => println("Oh no!") }
The OOP argument is false here. Sometimes OOP isn't the best way to describe declarative data. It surely allows you to implement this, but the cost is a much larger verbosity. The data type might be just a simple tagged union (in which case powerful optimizations can be used). Instead of writingenum node_type { sum_node, mul_node, ... } struct tree { node_type type; union { // bla bla } }
you can automatically eliminate the boilerplate code with this higher level construct. It's also much safer - unions are known to be a security loophole when used carelessly. Also with instanceof/cast() you may need to cast twice unlike in the match expression above.(1, (1,2)) match { case (1, (1, _)) => println("nice tuple") case _ => } def main(args: Array[Byte]) = args(0) match { case "-help" => println("Usage: ...") case "-moo" => println("moo") }
D already supports string switches.
I know that. The idea was to show how general pattern matching unifies the instanceof construct, integer switches, string switches and various kinds of algebraic data type manipulation such as tree/graph rewriting. It's a much more generalized construct in all possible ways - and very intuitive to use. Some of the beauty is lost when you read the example written in Scala, but e.g. in Haskell the pattern matching closely reflects the structure of the algebraic data type.
Mar 08 2010
Walter Bright <newshound1 digitalmars.com> wrote:foo match { case b: Bar => b.doBarMethod case b: Bar2 => b.doBar2Method case _ => println("Oh no!") } (1, (1,2)) match { case (1, (1, _)) => println("nice tuple") case _ => } def main(args: Array[Byte]) = args(0) match { case "-help" => println("Usage: ...") case "-moo" => println("moo") }
D already supports string switches.
Which means that D supports array switches (untested code): switch( (string)foo ) { case (string)[1,2,3]: doSomething( ); case (string)[3,2,1]: doSomethingElse( ); } Might require some tweaking, but I believe this would work. Not saying it's a good idea, though. As for structs: switch ( foo.toHash( ) ) { case S(1,2,3).toHash( ): doSomething( ); case S(3,2,1).toHash( ): doSomethingElse( ); } If toHash is CTFE-able. Just as untested, and might not work at all. -- Simen
Mar 08 2010
Sun, 07 Mar 2010 15:59:37 -0800, Walter Bright wrote:BCS wrote:I think (from context in other strands) that the OP was referring to value, not type, pattern matching.
Value pattern matching is just a regular switch statement.
So what types does the regular switch accept in D 2 ?
Mar 07 2010
retard wrote:The matching is all done at compile time, of course, and the delegate can be inlined.
I guess this tells a lot. No feature is added to D unless it can do something statically with zero runtime cost.
You did mention in another post in this thread that you were concerned about optimization?
Mar 07 2010
"retard" <re tard.com.invalid> wrote in message news:hn1717$24to$1 digitalmars.com...Having functional core constructs often helps in writing immutable functional code. Instead of first declaring a mutable variable and then assigning it a value later, with functional constructs you can immediately assign the result without requiring a mutable temporary state, e.g. int a = null; switch(b) { case foo: a = something; ... default: a = something_else; } vs const immutable int a = switch(b) { case foo: something; ... default: something_else; } The problem with mutability here is that after the assignment the mutable state doesn't automatically change.
That would also fit in very nicely with non-nullables and/or a system where it's an error to read a var before it's statically known to have be written to (instead of default init values).
Mar 09 2010
Sun, 07 Mar 2010 14:12:14 +0100, Lutger wrote:retard wrote:Sun, 07 Mar 2010 05:05:03 +0000, BCS wrote:Hello Jane,Is D a cult?
newsgroup yet. However I think Andrei's working on it and Don should have a patch in time for TDPL going out ;b
FWIW, I think there is a kernel of truth in the original claim. People tend to agree evey time Walter proposes a new feature such as built-in regexps - yes, they were removed shortly afterwards. But when bearophile or some retard propose some features from functional languages that are natural extensions to existing ones, everyone hates them and tells us to go back to our ivory towers.
That's weird, I don't see this at all. Maybe you focus too much on one or two negative comments? I also don't understand that you think D designers have a bias against functional programming, especially since the majority of the features that have been implemented the last years are heavily influenced by that style of programming.
Uh, majority of the features? From http://www.digitalmars.com/d/2.0/ features2.html:opAssign can no longer be overloaded for class objects.
nope Added pure keyword. [1]Extended enums to allow declaration of manifest constants.
nopeAdded const/immutable structs, classes and interfaces.
[1]Added const and immutable to IsExpressions.
nopeAdded typeof(return) type specifier.
[2]Added overloadable unary * operation as opStar().
nopeFull closure support added.
ok, but this is nothing special (c++0x, c# 3.5, java7, vb.net and everyone else already has this very basic feature)Transformed all of string, wstring, and dstring into immutable
[1]Added Overload Sets for functions and templates.
nopestd.math.sin, cos, tan are now evaluated at compile time if the argument
nopeAdded C++ interface for 'plugins'.
nopeChanged result type of IsExpression from int to bool.
nopeAdded optional TemplateParameterList to IsExpression.
nopeAdded warning when override is omitted.
nopeAdded new syntax for string literals (delimited, heredoc, D tokens)
nopeAdded __EOF__ token
nopeAdded D_Version2 predefined identifier to indicate this is a D version
nopeAdded .idup property for arrays to create immutable copies.
[1]Added transitive const and immutable.
[1]class and struct invariant declarations now must have a ().
nopeAdded isSame and compiles to __traits.
nopeAdded ForeachRangeStatement
Can't really tell whether this is functional or not. I know that C# LINQ (ZF expressions) can be considered a functional construct, but D2 foreach isn't really the same. Let's see what features I had in mind: - Algrebraic data types - Pattern matching (extension to enum/string/integer accepting switch) - Higher kinded types - Tuples (no auto-folding, real product types) - Built-in variants (real sum types) - Currying, lazy evaluation - Fusion optimizations (e.g. list and stream fusion) - Type classes - basic control constructs are expressions, not statements (e.g. unify if- then-else and : ? into a functional if-then-else) - better syntax for lambdas [1] if immutability is considered functional [2] if type inference is considered functional
Mar 07 2010
Sun, 07 Mar 2010 11:17:46 -0800, Walter Bright wrote:retard wrote:Let's see what features I had in mind: - Algrebraic data types
std.variant covers this.- Pattern matching (extension to enum/string/integer accepting switch)
Andrei and Sean have shown how to do that nicely with existing language features.
Really? I'd really like to see how this is done. Especially the nested matching of algebraic constructs, e.g. my_list match { case 1 :: 2 :: 3 :: tail => 123 :: tail } in D: if (list.getElemAt(0) == 1 && list.getElemAt(1) == 2 && list.getElemAt(2) == 3) { return list.new(123).append(list.range(3, list.length)); }- Currying, lazy evaluation
Already supports this.
I should have mentioned this http://enfranchisedmind.com/blog/posts/post-functional-scala/ That guy argues that even Scala isn't really functional since it doesn't encourage point-free programming with ugly and verbose partial application & currying. Indeed, both Scala and D support lazy evaluation in various contexts.- Fusion optimizations (e.g. list and stream fusion)
Andrei demonstrated how to do this neatly with ranges.
I really doubt he optimizes those since it requires serious compile time graph rewriting - possible with e.g. expression templates, though.- Type classes
Don't know what this is.
This is a bit related to the discussion about collection properties some time ago. And c++0x concept maps..- basic control constructs are expressions, not statements
Perhaps, but I still think it's necessary for D do be a { } Algol-style language. Nevertheless, I've demonstrated how this can be simply done using existing features.
Having functional core constructs often helps in writing immutable functional code. Instead of first declaring a mutable variable and then assigning it a value later, with functional constructs you can immediately assign the result without requiring a mutable temporary state, e.g. int a = null; switch(b) { case foo: a = something; ... default: a = something_else; } vs const immutable int a = switch(b) { case foo: something; ... default: something_else; } The problem with mutability here is that after the assignment the mutable state doesn't automatically change.(e.g. unify if-then-else and : ? into a functional if-then-else)
What's the difference between ?: and functional if-then-else?
Nothing. But you don't need both constructs. ?: should be the default as it is more general. I'd like to know why the return value should be discarded in the more common case. I know there's C/C++/Java compatibility arguments, but the original decision was somewhat flawed. I've worked in companies where the review process disallows the use of ?: because it makes the code look amateurish or 'hacky'.- better syntax for lambdas
The lambda syntax is as good as it's going to get without throwing out a *lot* of syntax compatibility.
Some other C/C++ based languages like C# seem to have done otherwise. The lambda in C# returns an expression like the ternary ?: in D so you don't need an explicit 'return'. The -> and => symbols are not used in D so I suppose it wouldn't be a big problem to extend the syntax with an expression returning lambda. After all, everything else is already there.[1] if immutability is considered functional [2] if type inference is considered functional
Several of your points are not, to my mind, fundamental issues of functional programming. To me, the foundations of FP are immutability, purity, and closures, which got a lot of attention. Most of your points are already supported by D, although not quite as conveniently as in many other languages.
There's the idealistic pure core in functional languages. Unfortunately no one really likes it because it's not that good for building practical programs. The features I mentioned above can be implemented with simple lambda expressions. The whole idea in many new functional language features is that they are straightforward to rewrite into lambdas. It's perfectly clear to me that no matter what you do, D won't become a functional language because the core runs on an imperative Turing machine. But the functional constructs can help building more readable and reliable code. That's why C# and Scala got those features..
Mar 07 2010
Hello retard,Sun, 07 Mar 2010 11:17:46 -0800, Walter Bright wrote:retard wrote:Let's see what features I had in mind: - Algrebraic data types
- Pattern matching (extension to enum/string/integer accepting switch)
language features.
matching of algebraic constructs, e.g. my_list match { case 1 :: 2 :: 3 :: tail => 123 :: tail } in D: if (list.getElemAt(0) == 1 && list.getElemAt(1) == 2 && list.getElemAt(2) == 3) { return list.new(123).append(list.range(3, list.length)); }
I'd rather the following over either: if(list[0..3] == [1,2,3]) return new list(123, list[3..$]);The -> and => symbols are not used in D so I suppose it wouldn't be a big problem to extend the syntax with an expression returning lambda. After all, everything else is already there.
While I'm not for it, how much harm would adding yet another form of the delegate expression cause? -- ... <IXOYE><
Mar 07 2010
"BCS" <none anon.com> wrote in message news:a6268ff10f2a8cc8c1b9f4d1252 news.digitalmars.com...Hello retard,Really? I'd really like to see how this is done. Especially the nested matching of algebraic constructs, e.g. my_list match { case 1 :: 2 :: 3 :: tail => 123 :: tail } in D: if (list.getElemAt(0) == 1 && list.getElemAt(1) == 2 && list.getElemAt(2) == 3) { return list.new(123).append(list.range(3, list.length)); }
I'd rather the following over either: if(list[0..3] == [1,2,3]) return new list(123, list[3..$]);
Expanding on that: if(list[0..3] == [1,2,3]) return new list(123, list[3..$]); if(list[2..4] == [10,11,12]) return new list(list[0..2], 200, list[4..$]); if(list[0..2] == [9,8]) return new list(100, list[3..$]); // Omit list[3] return list; Hmm. I'd rather something closer to this (purely hypothetical syntax, of course): return match(list) { case [1,2,3]~tail: 123~tail; case [a,b,10,11,12]~tail: [a,b]~200~tail; case [9,8]~tail: 100~tail[1..$]; default: list; }
Mar 09 2010
Tue, 09 Mar 2010 13:52:52 -0500, Nick Sabalausky wrote:"BCS" <none anon.com> wrote in message news:a6268ff10f2a8cc8c1b9f4d1252 news.digitalmars.com...Hello retard,Really? I'd really like to see how this is done. Especially the nested matching of algebraic constructs, e.g. my_list match { case 1 :: 2 :: 3 :: tail => 123 :: tail } in D: if (list.getElemAt(0) == 1 && list.getElemAt(1) == 2 && list.getElemAt(2) == 3) { return list.new(123).append(list.range(3, list.length)); }
I'd rather the following over either: if(list[0..3] == [1,2,3]) return new list(123, list[3..$]);
if(list[0..3] == [1,2,3]) return new list(123, list[3..$]); if(list[2..4] == [10,11,12]) return new list(list[0..2], 200, list[4..$]); if(list[0..2] == [9,8]) return new list(100, list[3..$]); // Omit list[3] return list; Hmm. I'd rather something closer to this (purely hypothetical syntax, of course): return match(list) { case [1,2,3]~tail: 123~tail; case [a,b,10,11,12]~tail: [a,b]~200~tail; case [9,8]~tail: 100~tail[1..$]; default: list; }
Your examples more or less suggest that you haven't used lists much. The reason why list pattern matching usually works the way I showed is that it's a simple linked list with a unbound payload type. Some typical use cases are: - find out whether the list is nil - return the head and tail - return n first elements and the tail Everything else costs a lot. The syntax encourages the thinking that extracting values is rather expensive and you shouldn't re-evaluate them. Indexing is O(n). You also very very very rarely jump over elements on the list. Lists can also be infinite in lazy languages so [1..$] makes little sense. So the example was a bit misleading. But if you see how lists are implemented with algebraic types, you might also see how other structures like trees (list is a degenerated tree) are matched.
Mar 09 2010
"retard" <re tard.com.invalid> wrote in message news:hn6c0p$875$1 digitalmars.com...Tue, 09 Mar 2010 13:52:52 -0500, Nick Sabalausky wrote:"BCS" <none anon.com> wrote in message news:a6268ff10f2a8cc8c1b9f4d1252 news.digitalmars.com...Hello retard,Really? I'd really like to see how this is done. Especially the nested matching of algebraic constructs, e.g. my_list match { case 1 :: 2 :: 3 :: tail => 123 :: tail } in D: if (list.getElemAt(0) == 1 && list.getElemAt(1) == 2 && list.getElemAt(2) == 3) { return list.new(123).append(list.range(3, list.length)); }
I'd rather the following over either: if(list[0..3] == [1,2,3]) return new list(123, list[3..$]);
if(list[0..3] == [1,2,3]) return new list(123, list[3..$]); if(list[2..4] == [10,11,12]) return new list(list[0..2], 200, list[4..$]); if(list[0..2] == [9,8]) return new list(100, list[3..$]); // Omit list[3] return list; Hmm. I'd rather something closer to this (purely hypothetical syntax, of course): return match(list) { case [1,2,3]~tail: 123~tail; case [a,b,10,11,12]~tail: [a,b]~200~tail; case [9,8]~tail: 100~tail[1..$]; default: list; }
Your examples more or less suggest that you haven't used lists much. The reason why list pattern matching usually works the way I showed is that it's a simple linked list with a unbound payload type. Some typical use cases are: - find out whether the list is nil - return the head and tail - return n first elements and the tail Everything else costs a lot. The syntax encourages the thinking that extracting values is rather expensive and you shouldn't re-evaluate them. Indexing is O(n). You also very very very rarely jump over elements on the list. Lists can also be infinite in lazy languages so [1..$] makes little sense. So the example was a bit misleading. But if you see how lists are implemented with algebraic types, you might also see how other structures like trees (list is a degenerated tree) are matched.
Well, I wasn't really thinking about lists specifically. I realize I wasn't clear on that, and probably should have renamed it "array" or something. I was just thinking about a much more general pattern matching construct, not just linked lists. Also, Andrei's pointed out in the past (convincingly, IMO) that a heavily list/head-and-tail type of thinking can lead to incorrect and suboptimal implementations (ie, the quicksort example). But, regardless of any of that, like I said, it was just hypothetical sample syntax. No more than a minute or two of thought put into it (hell, I can think of other problems with it right now). In fact, I was mainly just using it to point out that there's room for something much better than BCS's example.
Mar 09 2010
Hello retard,Lists can also be infinite in lazy languages so [1..$] makes little sense. So the example was a bit misleading. But if you see how lists are implemented with algebraic types, you might also see how other structures like trees (list is a degenerated tree) are matched.
The points you bring up I think support NOT adding this to D because there are so many cases that supporting them all in the language would get to messy. The most general case I think would work is, when the switch type is a user defined type, to allow any literal as the case labels as long as the switch type defines == for it and then require that the only one case compare as equals. With that requirement, the optimizer might be able to inline and fold a LOT of code in some cases. -- ... <IXOYE><
Mar 09 2010
Jane Doe wrote:Is D a cult?
Welcome back! :) Have you started understanding C++ yet? Ali "real"
Mar 07 2010
Walter Bright, el 7 de marzo a las 11:17 me escribiste:- Tuples (no auto-folding, real product types)
Tuples can be better, I agree.
Is nice to see that at least now you recognize that tuples can use some improvement. -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- Just because you're paranoid, don't mean they're not after you.
Mar 07 2010
Sun, 07 Mar 2010 14:52:09 -0800, Walter Bright wrote:retard wrote:It's perfectly clear to me that no matter what you do, D won't become a functional language because the core runs on an imperative Turing machine. But the functional constructs can help building more readable and reliable code. That's why C# and Scala got those features..
I'll reply to your other points later, but this one bothers me. Neither C# nor Scala support pure functions or immutable data structures, which are fundamental to FP. I don't see how they can be considered as supporting functional programming. http://en.wikipedia.org/wiki/Scala_(programming_language)
http://www.25hoursaday.com/weblog/CommentView.aspx?
Agreed, D 2 is rather unique among imperative languages. I guess no other imperative language provides such a transitive const system. The lack of strong const types sometimes bites you. On the other hand Scala does provide a shallow form of immutability and some immutable data structures in the standard library. I don't know if D2 provides any built-in immutable data structures. I guess just wrapping a data structure in immutable() won't suffice since there are probably some state changing functions in the mutable implementation that need to copy when dealing with immutable values. The good thing in Scala and C# is that they both provide nice tools for expressing functional problems without too much verbosity. When the const system in D works, I guess it solves the other part of the problem. Too bad you can't have them all without resorting to pure functional languages. In the functional language community they have been spending much time on the opposite, to find ways to add mutability into referentially transparent programs. Some examples: http://www.haskell.org/haskellwiki/DDC http://cs.anu.edu.au/~Ben.Lippmeier/project/thesis/thesis-lippmeier- sub.pdf https://www.cs.tcd.ie/Edsko.de.Vries/pub/ MakingUniquenessTypingLessUnique.pdf
Mar 07 2010
Sun, 07 Mar 2010 15:38:07 -0800, Walter Bright wrote:retard wrote:Sun, 07 Mar 2010 11:17:46 -0800, Walter Bright wrote:retard wrote:- Pattern matching (extension to enum/string/integer accepting switch)
language features.
Really? I'd really like to see how this is done.
foo( v, (int i) { writeln("I saw an int ", i); }, (string s) { writeln("I saw a string ", s); ), (Variant any) { writeln("I saw the default case ", any); } ); foo is a variadic template which takes its first argument, v, and attempts to match it with each delegate in turn. The first one that matches is executed.
Ok, that's pretty good. Now let's see how the pattern matching in Scala works: val a = 42 val b = 123 // basic matching of values a match { case 1 => println("You gave 1") case 2 => // functionality for 2 case _ => println("The default case") } // matching & refs to symbols a match { case `b` => println("You gave 123-1=122") case b => println("You gave " + b) } trait Spiny class Animal class Rabbit extends Animal class Hedgehog extends Animal with Spiny class Bear extends Animal object Roger extends Rabbit object Yogi extends Bear // matching & subtyping def foo(a:Animal) = a match { case Roger => "guess who framed you?" case Yogi => "o hai" case h: Animal with Spiny => "Possibly a hedgehog" case _ => "Giving up" } // nested matches { case a :: b :: c => 1 }: (List[Int] => Int) class Expr case class Value[T](v: T) extends Expr case class SumExpr(l: Expr, r: Expr) extends Expr case class MulExpr(l: Expr, r: Expr) extends Expr case class NegExpr(e: Expr) extends Expr def foo(e:Expr) = e match { case MulExpr(SumExpr(NegExpr(Value(1)), NegExpr(Value(5))), Value(2)) => println("Imagine, this could be used for AST processing") case _ => // do nothing } { case <html><a>some link</a></html> => println("found a link inside the DOM") }: (scala.xml.Elem => Unit) I left out some of the more complex functionality, e.g. extractors and more complex higher kinded stuff..The matching is all done at compile time, of course, and the delegate can be inlined.
I guess this tells a lot. No feature is added to D unless it can do something statically with zero runtime cost.
Mar 07 2010
Walter Bright <newshound1 digitalmars.com> wrote:retard wrote:On the other hand Scala does provide a shallow form of immutability and some immutable data structures in the standard library.
My experience with shallow const (in C++) is that it's nearly useless. Most C++ code I've seen seems to rely on an implicit assumption of transitive const, but it isn't in the documentation and of course you don't know if it is upheld or not. This is not conducive to reliable FP.
I still remember my first reading about D const, and thinking 'What? Other const regimes aren't transitive? That's madness!' -- Simen
Mar 08 2010
Mon, 08 Mar 2010 09:27:34 +0100, grauzone wrote:Walter Bright wrote:bearophile wrote:Walter Bright:There are significant technical problems with having functions return tuples.<
A possibly stupid question: isn't it enough to return a custom struct?
No, because of the alignment mismatches with other uses of tuples.
I don't understand, what does alignment have to do with such a high level construct?
Indeed, to me the tuple is just an interface. The compiler is free to optimize as much as it wants. The operational semantics are quite natural. I hadn't really thought about the systems programming context, but it sounds bad if it breaks the low level bit order in some cases.
Mar 08 2010
Mon, 08 Mar 2010 04:42:48 -0800, Walter Bright wrote:grauzone wrote:Again, I can't understand. Does the compiler rely that tuples have the same byte layout as structs or function arguments? I thought the compiler could just copy all fields. And the backend can already return multiple values, since it can return structs and static arrays.
A tuple and a struct composed of the same tuple should be interchangeable. This doesn't work, because the alignment is different for different circumstances.
Where does this requirement come from? Is there some existing work on some other language that tells one to implement it this way? A struct can have all kinds of aligments. The developer is able to choose this in a systems programming language. Implicit conversion from a tuple type to a arbitrary struct sounds like a flaw. Why are so many implicit conversions needed?
Mar 08 2010
On Mon, 08 Mar 2010 15:49:01 +0300, retard <re tard.com.invalid> wrote:Mon, 08 Mar 2010 04:42:48 -0800, Walter Bright wrote:grauzone wrote:Again, I can't understand. Does the compiler rely that tuples have the same byte layout as structs or function arguments? I thought the compiler could just copy all fields. And the backend can already return multiple values, since it can return structs and static arrays.
A tuple and a struct composed of the same tuple should be interchangeable. This doesn't work, because the alignment is different for different circumstances.
Where does this requirement come from? Is there some existing work on some other language that tells one to implement it this way? A struct can have all kinds of aligments. The developer is able to choose this in a systems programming language. Implicit conversion from a tuple type to a arbitrary struct sounds like a flaw. Why are so many implicit conversions needed?
I can't agree more.
Mar 08 2010
On Mon, 08 Mar 2010 07:51:31 -0500, grauzone <none example.net> wrote:bearophile wrote:grauzone:That aside, I'm also glad that you acknowledge that current tuples are not perfect and need improvement.
It's probably already too late to fix them,<
D2 is pretty much finalized now. The discussion (i.e. bikeshedding) alone to determine how tuples are done right would take much longer than this.
Technically, the book is finalized. Any details of D2 that are not in the book are allowed to be changed. That is, as long as it doesn't conflict with what the book says, it can be changed. This is why a complete documentation of phobos is not in the book (parts are referenced, and those parts must remain frozen). -Steve
Mar 08 2010
Tue, 09 Mar 2010 13:58:45 -0500, Nick Sabalausky wrote:"retard" <re tard.com.invalid> wrote in message news:hn1717$24to$1 digitalmars.com...Having functional core constructs often helps in writing immutable functional code. Instead of first declaring a mutable variable and then assigning it a value later, with functional constructs you can immediately assign the result without requiring a mutable temporary state, e.g. int a = null; switch(b) { case foo: a = something; ... default: a = something_else; } vs const immutable int a = switch(b) { case foo: something; ... default: something_else; } The problem with mutability here is that after the assignment the mutable state doesn't automatically change.
Of course, a nullable type is just a simple sum type and pattern matching works perfectly with algebraic types.and/or a system where it's an error to read a var before it's statically known to have be written to (instead of default init values).
They're better known as dataflow variables.
Mar 09 2010









"Nick Sabalausky" <a a.a> 