www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Is D a cult?

reply "Jane Doe" <JanisD comcast.net> writes:
Is D a cult? 
Mar 05 2010
next sibling parent "Nick Sabalausky" <a a.a> writes:
"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
prev sibling next sibling parent reply Justin Johansson <no spam.com> writes:
Jane Doe Wrote:

 Is D a cult? 

Did you mean occult? http://answers.yahoo.com/question/index?qid=20080701114449AAxUTtT
Mar 06 2010
parent FeepingCreature <default_357-line yahoo.de> writes:
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
prev sibling next sibling parent reply Bane <branimir.milosavljevic gmail.com> writes:
Jane Doe Wrote:

 Is D a cult? 
 
 

Compile Phobos backward to get the true message.
Mar 06 2010
parent div0 <div0 users.sourceforge.net> writes:
-----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
prev sibling next sibling parent Steve Teale <steve.teale britseyeview.com> writes:
On Sat, 06 Mar 2010 01:16:12 -0600, Jane Doe wrote:

 Is D a cult?

No but seriously ...
Mar 06 2010
prev sibling next sibling parent Chad J <chadjoan __spam.is.bad__gmail.com> writes:
Jane Doe wrote:
 Is D a cult? 
 
 

I think the word you are looking for is "hivemind" ;)
Mar 06 2010
prev sibling next sibling parent reply BCS <none anon.com> writes:
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
next sibling parent Bane <branimir.milosavljevic gmail.com> writes:
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
prev sibling parent reply Lutger <lutger.blijdestijn gmail.com> writes:
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
next sibling parent Lutger <lutger.blijdestijn gmail.com> writes:
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
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
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
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
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
prev sibling next sibling parent =?UTF-8?B?UGVsbGUgTcOlbnNzb24=?= <pelle.mansson gmail.com> writes:
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
prev sibling next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
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
next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
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
parent Walter Bright <newshound1 digitalmars.com> writes:
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
prev sibling parent reply James Iry <jamesiry gmail.com> writes:
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
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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
next sibling parent reply Henrik Huttunen <henrik.huttunen gmail.com> writes:
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
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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
prev sibling parent reply James Iry <jamesiry gmail.com> writes:
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
next sibling parent Bernard Helyer <b.helyer gmail.com> writes:
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
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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
next sibling parent reply grauzone <none example.net> writes:
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
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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
parent reply grauzone <none example.net> writes:
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
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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
parent reply grauzone <none example.net> writes:
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
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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
parent reply grauzone <none example.net> writes:
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
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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
parent grauzone <none example.net> writes:
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
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
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
parent reply grauzone <none example.net> writes:
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
parent reply Walter Bright <newshound1 digitalmars.com> writes:
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
parent grauzone <none example.net> writes:
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
prev sibling parent James Iry <jamesiry gmail.com> writes:
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
prev sibling parent Walter Bright <newshound1 digitalmars.com> writes:
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
prev sibling next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
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
parent reply bearophile <bearophileHUGS lycos.com> writes:
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
parent reply Walter Bright <newshound1 digitalmars.com> writes:
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
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
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
prev sibling next sibling parent BCS <none anon.com> writes:
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
prev sibling parent reply grauzone <none example.net> writes:
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
parent reply Walter Bright <newshound1 digitalmars.com> writes:
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
next sibling parent reply grauzone <none example.net> writes:
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
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
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
parent reply grauzone <none example.net> writes:
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
parent Walter Bright <newshound1 digitalmars.com> writes:
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
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
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
next sibling parent reply grauzone <none example.net> writes:
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
parent Walter Bright <newshound1 digitalmars.com> writes:
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
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
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
parent KennyTM~ <kennytm gmail.com> writes:
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
prev sibling parent Michel Fortin <michel.fortin michelf.com> writes:
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
prev sibling next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
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
next sibling parent reply BCS <none anon.com> writes:
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
parent reply Walter Bright <newshound1 digitalmars.com> writes:
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
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
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
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
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
next sibling parent reply BCS <none anon.com> writes:
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
parent reply Walter Bright <newshound1 digitalmars.com> writes:
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
parent reply Walter Bright <newshound1 digitalmars.com> writes:
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
parent reply BCS <none anon.com> writes:
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
parent Walter Bright <newshound1 digitalmars.com> writes:
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
prev sibling next sibling parent retard <re tard.com.invalid> writes:
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
prev sibling next sibling parent retard <re tard.com.invalid> writes:
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 writing
 enum 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
prev sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
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
prev sibling next sibling parent retard <re tard.com.invalid> writes:
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
prev sibling parent Walter Bright <newshound1 digitalmars.com> writes:
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
prev sibling parent "Nick Sabalausky" <a a.a> writes:
"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
prev sibling next sibling parent retard <re tard.com.invalid> writes:
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.

nope
Added const/immutable structs, classes and interfaces.

[1]
Added const and immutable to IsExpressions.

nope
Added typeof(return) type specifier.

[2]
Added overloadable unary * operation as opStar().

nope
Full 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.

nope
std.math.sin, cos, tan are now evaluated at compile time if the argument 

nope
Added C++ interface for 'plugins'.

nope
Changed result type of IsExpression from int to bool.

nope
Added optional TemplateParameterList to IsExpression.

nope
Added warning when override is omitted.

nope
Added new syntax for string literals (delimited, heredoc, D tokens)

nope
Added __EOF__ token

nope
Added D_Version2 predefined identifier to indicate this is a D version 

nope
Added .idup property for arrays to create immutable copies.

[1]
Added transitive const and immutable.

[1]
class and struct invariant declarations now must have a ().

nope
Added isSame and compiles to __traits.

nope
Added 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
prev sibling next sibling parent reply retard <re tard.com.invalid> writes:
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
next sibling parent reply BCS <none anon.com> writes:
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
parent "Nick Sabalausky" <a a.a> writes:
"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
prev sibling parent reply retard <re tard.com.invalid> writes:
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
next sibling parent "Nick Sabalausky" <a a.a> writes:
"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
prev sibling parent BCS <none anon.com> writes:
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
prev sibling next sibling parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
Jane Doe wrote:
 Is D a cult? 

Welcome back! :) Have you started understanding C++ yet? Ali "real"
Mar 07 2010
prev sibling next sibling parent Leandro Lucarella <llucax gmail.com> writes:
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
prev sibling next sibling parent retard <re tard.com.invalid> writes:
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
prev sibling next sibling parent retard <re tard.com.invalid> writes:
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
prev sibling next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
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
prev sibling next sibling parent retard <re tard.com.invalid> writes:
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
prev sibling next sibling parent retard <re tard.com.invalid> writes:
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
prev sibling next sibling parent "Denis Koroskin" <2korden gmail.com> writes:
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
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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
prev sibling parent retard <re tard.com.invalid> writes:
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