<div dir="ltr">Hi,<div>Call it curiosity, but I would also love to share something and look for a discussion around the following(and many people have noted this already).</div><div><br></div><div><span style="color:rgb(207,203,196)">" <b>So, if there is any proposal to put forth, in my view, it is to get rid of </b></span><span style="color:rgb(207,203,196)"><b>variable shadowing</b>."</span><br></div><div><br></div><div>If Erlang <b>drops</b> support for "v<b>ariable shadowing</b>", will it not help address the "<b>emergence</b>" that we are discussing about?</div><div><br></div><div>Even with <b>^-annotation</b> around, things are not addressed once and for all. The situation will only get avoided in the interim, but the likelihood of its reoccurrence still holds good. </div><div><br></div><div>As I could have a name whose first occurrence happens to be on line number 100, and all subsequent occurrences annotated with ^ in a defensive style. So far so good.Tomorrow I could embark on "Refactoring" fleet, and add some new code to the function around line 30-50, and endup naming one of my new variables to be the same as the one on line number 100. Situation, re-emerged. I need to go and attend these variables to deal with the situation. Or, I could embark on "Renaming" my variables to improve the "developer intent" for the sake of communication, even so I could lead to such a conflict. Even having the annotation capability around isn't helping too much for the problem which is being cited as the reason. </div><div><br></div><div>It's an <b>emergence</b>, and is owing to the way name<-> denotation association is handled in Erlang. Maybe we should try to deliberate more about the problem that the proposal is trying to address, and if there are options available which could keep Erlang closer to "minimalism" then I would prefer to go for that.   </div><div><br></div><div>Thanks and Regards</div><div>Nalin Ranjan </div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, Jan 20, 2021 at 6:16 PM Raimo Niskanen <<a href="mailto:raimo%2Berlang-questions@erlang.org">raimo+erlang-questions@erlang.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On Wed, Jan 20, 2021 at 01:47:12AM +0100, Chris Rempel wrote:<br>
> Hello,<br>
> <br>
> > I agree about the beauty of Erlang's simplicity. For this particular<br>
> > suggestion I, personally, feel that because Erlang "hides" if a variable<br>
> > occurence is a binding or a matching in the knowledge if the variable has<br>
> > occured before or not, it may be too simple because it is slightly ambigous.<br>
> ><br>
> > Therefore I think that although annotating matches would make the language<br>
> > less simple it would improve clarity by making intention explicit.<br>
> ><br>
> > I can live without this, have so for the last 20 years, but I think Erlang<br>
> > would be a slightly better language with pinning than it is without it.<br>
> ><br>
> > / Raimo Niskanen, Erlang/OTP, Ericsson AB<br>
> <br>
> I find a different conclusion in this, with how I think when coding in Erlang.<br>
> Knowing a variable always has the same value after first use, whether assigned<br>
> or pattern match, and the value never can change, is such simple concept to<br>
> work with.<br>
<br>
The proposal does not change that property.<br>
<br>
> <br>
> >From the EEP:<br>
> <br>
> f (X, Y) -><br>
>   case X of<br>
>     {a, Y} -> {ok ,Y};<br>
>     _ -> error<br>
>   end.<br>
> <br>
> would no longer be valid (at some point in the distant future when pinning is<br>
> mandatory), and would have to be written:<br>
> <br>
> f (X, Y) -><br>
>   case X of<br>
>     {a, ^Y} -> {ok ,Y};<br>
>     _ -> error<br>
>   end.<br>
> <br>
> yet today we can already write:<br>
> <br>
> f (X, Y) -><br>
>   case X of<br>
>     {a, Y2} when Y2 =:= Y -> {ok ,Y2};<br>
>     _ -> error<br>
>   end.<br>
> <br>
> So, for those who want this EEP in order to be more explicit, why do you not<br>
> write your code in that third form and introduce an EEP requesting a compiler<br>
<br>
I think that is too clumsy, just as it annoys me to have to do that when<br>
defining fun()s:<br>
    Y = value,<br>
    F = fun (YY) when YY =:= Y -> Y end,<br>
<br>
> flag that you can use to generate a warning in the first form above, so that<br>
> you rewrite it in the third form. The second form flies in the face of how I,<br>
> and apparently many others, think in Erlang. The pinning operator is<br>
> extraneous, and in fact determintal to that way of thinking.<br>
<br>
I have noticed the opinion that this breaks how they think about Erlang,<br>
and above you mentioned the principle that the same variable has the same<br>
value in all occurences.  I say that this proposal does not break that<br>
principle.<br>
<br>
So I have a hard time understanding exactly what way to think it is that the<br>
pinning operator destroys.<br>
<br>
    Y = foo(),<br>
    case bar() of<br>
        {ok, ^Y} -> {ok, Y}<br>
    end<br>
<br>
Y is the same variable and has the same value in all 3 occurences.<br>
But I know for sure that the code did not crash at Y = foo(), because<br>
Y can not have been previously bound.<br>
<br>
<br>
> <br>
> The good thing about this EEP is that it addresses variable shadowing.  It has<br>
> always bugged me that variable shadowing was a thing in Erlang.<br>
> <br>
> f(X, Y) -><br>
>   F = fun<br>
>     ({a, Y}) -> {ok, Y};<br>
>     (_) -> error<br>
>   end,<br>
>   {F(X), Y}.<br>
> <br>
> That generates the shadow variable warning currently, and `f({a, 1}, 2)`<br>
> returns `{{ok, 1}, 2}` which is just wrong as it breaks (in my view) the rule<br>
> that a variable value never changes.  And so pointlessly this must be<br>
> rewritten like so:<br>
> <br>
> f(X, Y) -><br>
>   F = fun<br>
>     ({a, Y2}) when Y2 =:= Y -> {ok, Y2};<br>
>     (_) -> error<br>
>   end,<br>
>   {F(X), Y}.<br>
> <br>
> The pinning operator "fixes" this by allowing for:<br>
> <br>
> f(X, Y) -><br>
>   F = fun<br>
>     ({a, ^Y}) -> {ok, Y};<br>
>     (_) -> error<br>
>   end,<br>
>   {F(X), Y}.<br>
> <br>
> But in both cases, I have to explicitly say, hey Erlang, don't break your own<br>
> rule that a variable value never changes. To me this EEP is fixing the problem<br>
> in the wrong way.<br>
<br>
I do not see how the pinning operator breaks the rule that a variable's<br>
value never changes.<br>
<br>
A variable's value never changes for all occurences of the variable in its<br>
scope.  The variable's scope is all of the function after its first occurence.<br>
<br>
When we get to fun()s we have a conflict of principles.  Should the<br>
the same scoping rule apply to the fun() as to the surrounding function?<br>
<br>
Erlang has solved this with a pragmatic compromise (as often enough):<br>
variables bound in a fun() are local to the fun().  But variables from the<br>
outer scope that are referred to in a fun() are from the outer scope.  So<br>
if it has the same name it is the one in the outer scope.  Except in the<br>
fun() argument list.  Here variables are in general new ones so they are<br>
local to the fun(), even if a different variable with the same name exists<br>
in the outer scope.<br>
<br>
But a variable's value never changes within its scope.  Not today.<br>
Not with this proposal.  The snag is; which variable do we mean?<br>
<br>
> <br>
> So, if there is any proposal to put forth, in my view, it is to get rid of<br>
> variable shadowing.<br>
<br>
You are free to sketch on one; it does not have to be an EEP.<br>
<br>
A problem is that today variables in a fun() head shadows variables from<br>
the outer scope, and the compiler warns about it.  If the behaviour should<br>
be changed into not shadowing variables the compiler could not warn about<br>
using a variable from the outer scope because it is now assumed that it is<br>
the correct semantics.  If there was an annotation of the variables that<br>
are bound instead of matched the compiler could tell the difference.  Such<br>
an annotation would very much look like variable rebinding and could easily<br>
be extended to exactly that.<br>
<br>
Another possibility would be to introduce some kind of let...end construct<br>
to explicitly introduce variable scoping, which has been discussed before.<br>
<br>
There might, of course, be other possibilities.<br>
I am not a language expert.<br>
<br>
> <br>
> Also, already in this thread it is now being mentioned to have variable<br>
> rebinding support. If this EEP erodes such a core tenant (in my view) of<br>
> Erlang such that it leads to variable rebinding, it should be rejected on that<br>
> alone (in my view).<br>
<br>
I also do not want to get variable rebinding.  But this EEP should be<br>
evaluated on its own merits and on the possibilities it offers that we<br>
might want.<br>
<br>
> <br>
> But the part of the EEP that just completely nullifies it is:<br>
> <br>
> > In this case, there is no new binding of Y, and the use of Y in the fun<br>
> > clause body refers to the function parameter. But it is also possible to<br>
> > combine pinning and shadowing in the same pattern:<br>
> ><br>
> > f(X, Y) -><br>
> >     F = fun ({a, ^Y, Y})  -> {ok, Y};<br>
> >             (_) -> error<br>
> >         end,<br>
> >     F(X).<br>
> ><br>
> > In this case, the pinned field refers to the value of the function function<br>
> > parameter, but there is also a new shadowing binding of Y to the third field<br>
> > of the tuple. The use in the fun clause body now refers to the shadowing<br>
> > instance.<br>
> <br>
> You now have two variables named the same thing with different values. It<br>
> breaks fundamental way of thinking in Erlang.  There is zero value in allowing<br>
> this. Use a different variable name.<br>
<br>
I agree that anyone that writes code like that deserves a good telling<br>
off...<br>
<br>
I think the problem is in the variable shadowing, not in the pinning operator.<br>
Today we get a compiler warning when a variable in a fun() head shadows one<br>
in the outer scope.  But other than that it is legal.<br>
<br>
We do not, however, get a warning when a variable is used in a fun() body<br>
from the surrounding function since a fun() body has got the same scope as<br>
the surrounding function, except for newly bound variables...  Accidentally<br>
referring to a variable from outside the fun() is a problem.<br>
<br>
With the pinning operator it becomes possible to explicitly refer to the<br>
outer scope and thereby possible to warn for referring to the containing<br>
function without being explicit, making the fun() more a real variable<br>
scope.<br>
<br>
> <br>
> The EEP Rationale section is likewise problematic, but copying it here and<br>
> responding to each point is tiresome.<br>
<br>
That was some handwaving.  You are stating that it is problematic without<br>
explaining why.  Not very constructive.<br>
<br>
> <br>
> So, I'd like to propose that any EEP added to <a href="https://github.com/erlang/eep/" rel="noreferrer" target="_blank">https://github.com/erlang/eep/</a><br>
> is done in a PR and left open for reviews/comments on the PR for a period of<br>
> time. There is much in the EEP that I would comment on, line by line.<br>
<br>
That is an interesting suggestion.  EEP 1 states that after an EEP has been<br>
accepted (not approved) it should try to get community support, but it does<br>
not say how.<br>
<br>
The current situation where this EEP is discussed in <a href="mailto:eeps@erlang.org" target="_blank">eeps@erlang.org</a>,<br>
<a href="mailto:erlang-questions@erlang.org" target="_blank">erlang-questions@erlang.org</a>, and in the PR for the reference implementation<br>
is not good.<br>
<br>
Having discussions about the EEP before submission (and after(?)) in a pull<br>
request on the eep repository on GitHub sounds like a good step, except for<br>
the ones that do not have accounts on GitHub, and it would drive us further<br>
into the GitHub (/Microsoft) hands, which may be politically sensitive.<br>
<br>
> <br>
> There has been concern on the list that this discussion has not remained<br>
> technical and on point to the value of the EEP, and I would suggest the fault<br>
> lies in the tool being used to elicit feedback (e-mail). That concern would be<br>
> addressed by allowing people to comment line by line on the EEP and discuss<br>
> the specific points of the EEP in the PR itself. And we can avoid blame being<br>
> thrown around about people having or not having read the EEP.<br>
<br>
A very valid point.  I also think GitHub Pull Requests offer better<br>
possibilities for discussion around details.<br>
<br>
> <br>
> Regards,<br>
> <br>
> Chris<br>
<br>
-- <br>
<br>
/ Raimo Niskanen, Erlang/OTP, Ericsson AB<br>
</blockquote></div>