I want to be able to retrieve a value and then branch on its value, all in
one step. For some reason it irks me to have to say:
var blah = GetBlah();
if(blah != null)
{
//Do Stuff With blah
}
I want to say
if((var blah = GetBlah) != null)
{
//Do stuff with blah
}
I'm not sure why the extra line bothers me - possibly because it's a
pattern I keep having to repeat in my code, and any pattern I repeat irks
me after a while. That's why computers are there, to stop you having to do
the same thing over and over again.
one step. For some reason it irks me to have to say:
var blah = GetBlah();
if(blah != null)
{
//Do Stuff With blah
}
I want to say
if((var blah = GetBlah) != null)
{
//Do stuff with blah
}
I'm not sure why the extra line bothers me - possibly because it's a
pattern I keep having to repeat in my code, and any pattern I repeat irks
me after a while. That's why computers are there, to stop you having to do
the same thing over and over again.
no subject
Date: 2011-06-20 12:44 pm (UTC)no subject
Date: 2011-06-20 12:49 pm (UTC)no subject
Date: 2011-06-20 12:52 pm (UTC)var blah; if ((var = getBlah()) != null) { //Do stuff with blah }?
no subject
Date: 2011-06-20 01:12 pm (UTC)no subject
Date: 2011-06-21 09:17 am (UTC)(no subject)
From:no subject
Date: 2011-06-20 01:13 pm (UTC)(blah = getBlah())returns the value assigned to blah.You'd have to declare blah without using "var" though, unless there's an assignment on the same line the type inference has nothing to work on.
so this works
string blah;
if ((blah = getBlah()) != null)
{
//Do stuff with blah
}
private string getBlah()
{ ... }
no subject
Date: 2011-06-20 01:34 pm (UTC)Ah yes, I'd forgotten that C# has type inference; I'd assumed that Andy's '
var' was pseudocode, heh.(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:no subject
Date: 2011-06-20 07:18 pm (UTC)However, I don't think I _want_ to write what Andy wanted to write. I think the assignment and test together are two ugly. I would accept a syntax like:
or:
or possibly some other convenient shorthand.
In C++ it might be possible to make an awful preprocessor hack, something like
#define TRY(var, value) for(auto var = value;var!=null;var=null) TRY(blah, GetBlah()) { // do stuff }You mgiht be able to improve the semantics, I'm not sure. I doubt it's worth using, though. You may be able to do something fancier with templates, but it's getting it to act like an "if" statement that's hard.
no subject
Date: 2011-06-20 08:05 pm (UTC)no subject
Date: 2011-06-20 08:46 pm (UTC)if (blahType blah = GetBlah()) { ... }(no subject)
From:no subject
Date: 2011-06-20 12:53 pm (UTC)The closest you could get in C# would be an extension method using some generics and lambdas:
public static T DoIfNotNull<T>(this T value, Action<T> action) where T: class
{
if (value != null)
{
action(value);
}
// return the value for further chaining
return value;
}
Then you could code:
GetBlah().DoIfNotNull(blah => DoStuffWith(blah));of course there are variations on this like
public static U DoIfNotNull<T, U>(this T value, Func<T, U> func) where T : class
{
U result = default(U);
if (value != null)
{
result = func(value);
}
return result;
}
.. so then your action can change the type and you can still chain methods.
no subject
Date: 2011-06-20 01:10 pm (UTC)(no subject)
From:(no subject)
From:no subject
Date: 2011-06-20 01:17 pm (UTC)http://metoojava.wordpress.com/2010/11/15/java-7-awesome-features/
It's an interesting language feature I've not seen elsewhere that I hope spreads.
no subject
Date: 2011-06-20 02:01 pm (UTC)no subject
Date: 2011-06-20 05:12 pm (UTC)You can say
if (my $blah = get_blah()) {
...
}
but not
if (my $blah = get_blah() and $blah->can('do_stuff')) {
$blah->do_stuff();
}
because $blah doesn't exist when the second part of the conditional is run. You need to say
if (my $blah = get_blah()) {
if ($blah->can('do_stuff')) {
$blah->do_stuff();
}
}
instead.
no subject
Date: 2011-06-20 09:05 pm (UTC)package fail; sub AUTOLOAD { return $_[0]; } use constant FAIL => bless [], fail; package blah; sub doStuffWithBlah { ...; return $self; } sub doMoreStuffWithBlah { ...; return $self; } package main; sub getBlah { ... else { return FAIL; } } getBlah()->doStuffWithBlah()->doMoreStuffWithBlah();If getBlah returns FAIL, then 'doStuffWithBlah' resolves to fail::AUTOLOAD, which does nothing but return FAIL, allowing 'doMoreStuffWithBlah' to resolve to fail::AUTOLOAD also, so the failing behaviour cascades.
...and I'm just going to stop right there, because, frankly, it's quite silly, isn't it?
no subject
Date: 2011-06-20 06:49 pm (UTC)It also strongly reminds me of Icon's goal-directed evaluation, but since Icon doesn't have any OO features and very very limited structures, I'm pretty sure it doesn't have anything quite like this; but if it *did*, it would support this sort of thing straight out of the box.
(I recommend giving Icon a once-over for curiosity's sake, by the way; it's an interesting little language, primarily because of the goal-oriented evaluation and generation. )
no subject
Date: 2011-06-20 07:56 pm (UTC)no subject
Date: 2011-06-20 08:06 pm (UTC)There ought to be a good way of saying "Is there an X? If so, do stuff with it?", and I don't think I've found that just yet.
(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:no subject
Date: 2011-06-20 10:44 pm (UTC)var blah = GetBlah();
if (blah == null) return;
// Do Stuff With blah
Or:
var blah = GetBlah();
if (blah == null) continue;
// Do Stuff With blah
no subject
Date: 2011-06-21 08:56 am (UTC)(no subject)
From:(no subject)
From:no subject
Date: 2011-06-21 11:41 am (UTC)The second approach saves one line of source code, but if the compiler is in any way decent, it will be no better when run.
no subject
Date: 2011-06-21 12:24 pm (UTC)no subject
Date: 2011-06-21 11:42 am (UTC)F# has a pipeline operator "|>" which is just a syntactic re-arrangement, so that aList |> filter |> sort is equivalent to sort(filter(aList). It's for readability more than anything else. "the list is filtered then sorted" is clearly expressed in the pipeline version, even though it's equivalent to the other version. What's interesting is that |> can be defined inside F#, so your operator couldn't be too hard....
I found out that, at least for the novice, F# is a language where typing the brief code is the least of your worries. Understanding what's going on takes far longer. This took a while.
F# does nulls with the option / Some / None constructs. anything without these cannot be null.
Herewith some code and commentary from the F# interactive console:
Microsoft (R) F# 2.0 Interactive build 4.0.40219.1 Copyright (c) Microsoft Corporation. All Rights Reserved. For help type #help;; > let increment a = a + 1;; val increment : int -> int I have defined a function called 'increment'. F# has deduced that the type of it is 'int -> int' > 42 |> increment;; val it : int = 43 I can use the pipeline operator to pipeline 42 into increment and get 43 > let (|+) a fn = fn a ;; val ( |+ ) : 'a -> ('a -> 'b) -> 'b I can define my own operator that works just like the pipeline. It also has a type, and the second input is a function a -> b. > 42 |+ increment;; val it : int = 43 .. and it works the same > let (|++) a fn = if Option.isSome(a) then Some(fn(Option.get(a))) else None;; val ( |++ ) : 'a option -> ('a -> 'b) -> 'b option Here is the 'DoIfNull' operator. If it was called 'DoIfNull' it wouldn't be an infix operator, apprently operators can't be named in the alphabet. Also now the types are those that can be null, and I need to wrap values in Some() to make them nullable again. Getting this to work took a while. > Some(1) |++ increment;; val it : int option = Some 2 > Some(42) |++ increment;; val it : int option = Some 43 But I can use it, it will increment a nullable int > None |++ increment;; val it : int option = None And it will leave a null int alone > let (|++) a fn = match a with | Some(x) -> Some(fn(x)) | None -> None;; val ( |++ ) : 'a option -> ('a -> 'b) -> 'b option > Some(42) |++ increment;; val it : int option = Some 43 A slightly different but equivalent defintion of the same operator With more complex types: let numbers = [1..10];; val numbers : int list = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10] > let isEven i = i % 2 = 0;; val isEven : int -> bool > numbers |> List.filter isEven;; val it : int list = [2; 4; 6; 8; 10] > Some(numbers) |++ List.filter isEven;; val it : int list option = Some [2; 4; 6; 8; 10] >no subject
Date: 2011-06-21 12:33 pm (UTC)And I know what you mean about the code being easier to write rather than read. That's one of the advantages of c# - people can read it reasonably easily (at least for the basics), and it's harder to get confused as to what's going on inside.
(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From: