www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Where statement

reply bearophile <bearophileHUGS lycos.com> writes:
Some people have proposed the introduction in Python of the 'where' statement.
It is quite used in Haskell:

printFreqsBySize genome keySize = do
        ht0 <- htNew keySize
        ht <- hashGenome genome keySize ht0
        l <- htToList ht
        htFree ht
        return $ map draw (sortBy sortRule l) ++ [""]
    where
        genomeLen = S.length genome
        draw :: (S.ByteString, Int) -> String
        draw (key, count) = printf "%s %.3f" (S.unpack key) pct
            where pct   = (100 * (fromIntegral count) / total) :: Double
                  total = fromIntegral (genomeLen - keySize + 1)



In some situations it improves readability of complex epressions. It also keeps
the namespace clean because here "a" and "b" names are local to the where
block. So only "c" exist when the 'where' block ends:

c = sqrt(a*a + b*b) where:
    a = retrieve_a()
    b = retrieve_b()

That is equivalent to:

c = (retrieve_a() ** 2 + retrieve_b() ** 2) ** 0.5


Another of its possible usages in Python is to define Ruby-like blocks (that is
multiline lambdas):

obj.onclick.setcallback(f) where:
    def f(x, y):
        # callback body here ...


D lambdas can be multiline, so that's not a problem.
But it can be useful to write more readable expressions when they are complex:

auto c = sqrt(a*a + b*b) where {
    auto a = retrieve_a();
    auto b = retrieve_b();
}


In this case you can write a single expression in D too:
import std.math;
auto c = (retrieve_a() ^^ 2 + retrieve_b() ^^ 2) ** 0.5;


With a single expression you don't need brackets:

double d = sqrt(x*x + y*y) where
    double x = computeX();

Bye,
bearophile
Jul 25 2010
next sibling parent reply Trass3r <un known.com> writes:
 c = sqrt(a*a + b*b) where:
     a = retrieve_a()
     b = retrieve_b()

 That is equivalent to:

 c = (retrieve_a() ** 2 + retrieve_b() ** 2) ** 0.5

You immediately give the counter-argument? ^^ Introducing a new keyword + whole new constructs gotta have substantial merit. The 2nd concept is perfect to me, some parentheses are no reason. Another possibility would probably be the following, but it's not as compact and nice: double c; { double a = retrieve_a(); double b = retrieve_b(); c = sqrt(a*a + b*b); }
Jul 25 2010
parent bearophile <bearophileHUGS lycos.com> writes:
Trass3r:

You immediately give the counter-argument? ^^<

I try to give both pros and cons :-) I think when expressions get even more complex 'where' can help.
 Another possibility would probably be the following, but it's not as  
 compact and nice:
 
 double c;
 {
         double a = retrieve_a();
         double b = retrieve_b();
 
         c = sqrt(a*a + b*b);
 }

If 'c' has a very complex type, you really want to use 'auto', but you can't there. In functional-style programming types can be very complex and long to write, for example the result of a map(filter(lazy generator)). Bye, bearophile
Jul 25 2010
prev sibling next sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2010-07-25 08:33:53 -0400, bearophile <bearophileHUGS lycos.com> said:

 D lambdas can be multiline, so that's not a problem.
 But it can be useful to write more readable expressions when they are complex:
 
 auto c = sqrt(a*a + b*b) where {
     auto a = retrieve_a();
     auto b = retrieve_b();
 }

Is this really an improvement over using a delegate literal? auto c = { auto a = retrieve_a(); auto b = retrieve_b(); return sqrt(a*a + b*b); }; -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Jul 25 2010
next sibling parent Trass3r <un known.com> writes:
 Is this really an improvement over using a delegate literal?

 	auto c = {
 		auto a = retrieve_a();
 		auto b = retrieve_b();
 		return sqrt(a*a + b*b);
 	};

Even more clever.
Jul 25 2010
prev sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Michel Fortin:
 Is this really an improvement over using a delegate literal?
 
 	auto c = {
 		auto a = retrieve_a();
 		auto b = retrieve_b();
 		return sqrt(a*a + b*b);
 	};

Cute :-) I have never seen this used in D code. I think you will need to add () at the end when property get implemented fully. I hope the D compiler is able to inline that delegate. Bye, bearophile
Jul 25 2010
parent Michel Fortin <michel.fortin michelf.com> writes:
On 2010-07-25 09:48:21 -0400, bearophile <bearophileHUGS lycos.com> said:

 Michel Fortin:
 Is this really an improvement over using a delegate literal?
 
 	auto c = {
 		auto a = retrieve_a();
 		auto b = retrieve_b();
 		return sqrt(a*a + b*b);
 	};

Cute :-) I have never seen this used in D code. I think you will need to add () at the end when property get implemented fully.

Indeed, I forgot to add the (). Without it the type of 'c' is a delegate (whether property is implemented or not is irrelevant). I just didn't test it properly before posting. Here's the revised version: auto c = { auto a = 1.0; auto b = 2.0; return a*a + b*b; }(); I've never seen this in use either, but it looks like a nice pattern for variables that require a complex initialization.
 I hope the D compiler is able to inline that delegate.

I think it does not currently. This bug report turns out to have a patch for this exact issue however: <http://d.puremagic.com/issues/show_bug.cgi?id=4440> Put your vote on it if you want. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Jul 25 2010
prev sibling next sibling parent Kagamin <spam here.lot> writes:
bearophile Wrote:

 auto c = sqrt(a*a + b*b) where {
     auto a = retrieve_a();
     auto b = retrieve_b();
 }

the where statement looks as a declaration statement, but scoped block allows arbitrary statements.
Jul 25 2010
prev sibling parent reply Tomek =?UTF-8?B?U293acWEc2tp?= <just ask.me> writes:
bearophile wrote:

 Some people have proposed the introduction in Python of the 'where'
 statement. It is quite used in Haskell:
 
 printFreqsBySize genome keySize = do
 ht0 <- htNew keySize
 ht <- hashGenome genome keySize ht0
 l <- htToList ht
 htFree ht
 return $ map draw (sortBy sortRule l) ++ [""]
 where
 genomeLen = S.length genome
 draw :: (S.ByteString, Int) -> String
 draw (key, count) = printf "%s %.3f" (S.unpack key) pct
 where pct   = (100 * (fromIntegral count) / total) :: Double
 total = fromIntegral (genomeLen - keySize + 1)

It exists in Haskell because functional languages can't describe sequences (can't declare a temporary variable before the main expression because there's no "before"). But I don't know Haskell so I may be wrong. Anyway, where in D wouldn't bring enough return of investment to break even, IMHO. Tomek
Jul 25 2010
parent KennyTM~ <kennytm gmail.com> writes:
On Jul 25, 10 21:54, Tomek SowiƄski wrote:
 bearophile wrote:

 Some people have proposed the introduction in Python of the 'where'
 statement. It is quite used in Haskell:

 printFreqsBySize genome keySize = do
 ht0<- htNew keySize
 ht<- hashGenome genome keySize ht0
 l<- htToList ht
 htFree ht
 return $ map draw (sortBy sortRule l) ++ [""]
 where
 genomeLen = S.length genome
 draw :: (S.ByteString, Int) ->  String
 draw (key, count) = printf "%s %.3f" (S.unpack key) pct
 where pct   = (100 * (fromIntegral count) / total) :: Double
 total = fromIntegral (genomeLen - keySize + 1)

It exists in Haskell because functional languages can't describe sequences (can't declare a temporary variable before the main expression because there's no "before"). But I don't know Haskell so I may be wrong.

No. quadraticSum a b = let aSquared = a*a bSquared = b*b in aSquared + bSquared
 Anyway, where in D wouldn't bring enough return of investment to break even,
 IMHO.


 Tomek

Jul 25 2010