[erlang-questions] I think I wish I could write case Any of whatever -> _ end.

Eric Newhuis (personal) enewhuis@REDACTED
Tue May 18 05:25:18 CEST 2010


The specific case I've had a number of times is when writing short filter functions that either pass through or modify something.

I'd find myself almost forced to write the following:

case find(...) of
	error ->
		{ok, Default};
	{ok, Value} ->
		{ok, Value}
end.

And the reconstruction of a small tuple bugged me.  Your suggestion shortens this to something arguably easier to type.

case X = find(...) of
	error ->
		{ok, Default};
	{ok, Value} ->
		X
end.

...without the apparent overhead of reconstruction.  (Is it a moot point due to a clever compiler?)

But I guess I am still concerned about suggesting this as a general programming idiom because it introduces a temporary variable.  And as such one would need to study pre- and post-logic to avoid accidental use of the same variable name to name something different.

I'd not have this concern if Erlang had a LET construct:

let X = find(...) in
	case X of
		error ->
			{ok, Default};
		{ok, Value} ->
			X
	end.

Variable scope is important.  Of course...absurdly...

(fun() ->
	case X=find(...) of
		error ->
			{ok, Default1};
		{ok, Value} ->
			X
	end
end)(),
(fun() ->
	case X=obviously_different_fetch(...) of
		error ->
			{ok, Default2};
		{ok, Value} ->
			X
	end
end)().

But that is ridiculous.

So apparently my idea isn't so great.  And I also don't have a satisfying temporary-free and reconstruction-free solution.


On May 17, 2010, at 6:09 PM, Richard O'Keefe wrote:

> 
> On May 18, 2010, at 2:00 AM, Eric Newhuis (personal) wrote:
> 
>> For the record, I might still disagree, so far.  I'm not sure.  Simply for argument's sake...
>> 
>> The context in which this might be maximally useful is the following.
>> 
>> case some_module:some_function(...) of
>> 	{some, pattern} -> _;
>> 	{some, other, pattern} -> _;
>> 	_ -> whatever
>> end.
> 
> What is wrong with
> 
>    case X = some_module:some_function(...)
>      of {some, pattern} -> X
>       ; {some, other, pattern} -> X
>       ; _ -> whatever
>    end
>> 
>> Note that I belong to the school of philosophy that suggests that the number of temporary variables should be minimized.
> 
> By using the wild card, you have *NOT* minimised the number of temporary
> variables.  All you have done is to carefully deprive your reader of any
> clues as to what it is about.
> 
> 
>> I don't understand why the above would be called wild-card abuse.
> 
> Because the whole *point* of the wild-card is that each and
> every occurrence of "_" should represent a DIFFERENT variable.
> That's what it means in Prolog, Mercury, Strand88, Parlog, GHC,
> ML, Haskell, Clean, ...  Every time, a different variable.
> But you are relying on the "_" in each arm of the case being
> the *SAME* variable.
> 
> You are also creating great confusion.
> Suppose I have
> 
> 	case foo()
> 	  of {ping,_} -> _
> 	   ; {_,pong} -> _
> 	end
> 
> The wild cards *following* the arrows are the *same* variable;
> what about the wild cards inside the patterns?  If not, why not?
> 
> What if I write
> 	case foo() of _ -> case bar() of _ -> _ end end
> Does this mean the same as
> 	case foo() of X -> case bar() of X -> X end end
> or	case foo() of X -> case bar() of Y -> X end end
> or	case foo() of X -> case bar() of Y -> Y end end
> or what?
> 
> There's another point.  In Erlang as it stands, _every_
> variable _without exception_ must be visibly present at
> the point where it is bound.  (Wild cards are no exceptions
> to this rule).  You are introducing a new reading of "_"
> that violates this rule.  If you want to think of the
> variable as bound in the pattern, write
> 	case Expr
> 	  of X = Pattern when Guard -> X
> If you want to think of the variable as bound in the head,
> write
> 	case X = Expr
> 	  of Pattern when Guard -> X
> In either case, the variable X is *visibly* bound.
> 
>> It is clear from context that the wild-card represents something other than matching.
> 
> Yes, but we already *have* something we can use for this purpose.
> Ordinary variable names.
> 
> 
>> We've seen this idea before.  There are those grammars that expose variables whose value is whatever matched.
> 
> I have no idea what you are referring to.  Can you explain?
> 
> "Exposing variables" is different from "invisibly binding anonymous
> variables".
> 
>> 
>> I suppose the following is where this great idea of mine might break down.
>> 
>> case some_module:some_function(...) of
>> 	{some, pattern} ->
>> 		{encapsulated, _};
>> 	{some, other, pattern} ->
>> 		{another, _, encapsulation}
>> end.
>> 
>> Although I still don't have a problem with that.
> 
> You may not.  I do.
> 
>> From context I know that the right hand side of the arrow isn't pattern matching.
> 
> You as author may; your reader WILL have to work harder in reading
> to find out what the context *is*, especially if (as is often the
> case) the arrow is on the previous screen.
> 
> This would be better as
> 
> 	case X = some_module:some_function(...)
> 	  of {some, pattern} ->
> 	         {encapsulated, X}
> 	   ; {some, other, pattern} ->
> 	         {another, X, encapsulation}
> 	end
> 
> There is not one of your examples that would not be massively improved
> by introducing a named variable, even a literal X.
>> 
>> I guess where readability might break down is in nesting:
>> 
>> case some_module:some_function(...) of
>> 	{some, _, pattern} -> % _1
>> 		case _ of ->  % _2
>> 			{some, great, pattern} ->
>> 				not_so_bad;
>> 			_ -> % _3
>> 				{_, Kind, _} = _, % _4, _5, _6
>> 				Kind
>> 		end
>> end.
>> 
>> Although I can still read the above once I learn that underscore ('_') is context sensitive.
>> 
>> _1 :: any()
>> _2 :: {some, any(), pattern}
>> _3 :: {some, any(), pattern}, not {some, great, pattern}
>> _4 :: some
>> _5 :: pattern
>> _6 :: _3
> 
> If I want to play at silly puzzles I do the Sudoku problem in the
> newspaper.  If I'm reading a program, I do *NOT* enjoy pointless
> stumbling-blocks placed in my path to understanding.
> 
> Let's rewrite your example.
> 
> 	case some_module:some_function(...)
> 	  of {some,Kind,pattern} ->
> 	         case Kind
>                   of great -> not_so_bad
> 		      _     -> Kind
> 		 end
> 	end
> 
> There is now *no* puzzle-solving for the reader.
> 
> Let me raise my usual refrain:
> 	let's have a REAL example.
> 
> 



More information about the erlang-questions mailing list