Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: With block with variable declaration to allow local scope and object Ref #438

Open
VBAndCs opened this issue May 10, 2019 · 35 comments

Comments

@VBAndCs
Copy link

VBAndCs commented May 10, 2019

Combining this #437 (comment) with this #393
We can have a new local scope like this:

If condition Then
    Dim x = 1
End If  

With X = "Test"
     ' This is a local scope to use X
End With

With X As Integer = 0
     ' This is a local scope to use X
End With

With X = Form1 
     ' use X as a ref for Form1
       X.Show()
     ` or use the . directly
     .Hide()
End With
@VBAndCs VBAndCs changed the title Proposal: Using-Like with block to allow local scobe and object alias Proposal: With block with variable declaration to allow local scope and object Ref May 11, 2019
@rskar-git
Copy link

Realize that equals sign (=) has two roles in VB: assignment and equality-test.

Hence, With X = "Test" and With X = Form1 cannot be used to introduce a locally scoped X, because that would be a breaking change - = in both cases means equality-test.

With X As Integer = 0 interferes with any idea of using As for typecasting/conversion.

Perhaps Dim can be of use here? E.g.:

With Dim X = "Test"
     ' This is a local scope to use X
End With

With Dim X As Integer = 0
     ' This is a local scope to use X
End With

With Dim X = Form1 
     ' use X as a ref for Form1
       X.Show()
     ` or use the . directly
     .Hide()
End With

Indeed, Dim already supports a list of variable declarations, so this could also be possible:

With Dim X = Form1, Y As String = "abc", Z As Integer = 0
     ' This is a local scope to use X, Y, and Z
	 ' ...
	 .Hide()  ' Unqualified means first variable in list - X in this case.
End With

@zspitz
Copy link

zspitz commented May 11, 2019

@rskar-git The LDM's syntax for introducing variables in pattern matching (suggested by @AdamSpeight2008) could also be used here:

With "Test" Into X
     ' This is a local scope to use X
End With

With 0 Into X As Integer
     ' This is a local scope to use X
End With

With Form1 Into X
     ' use X as a ref for Form1
       X.Show()
     ` or use the . directly
     .Hide()
End With

@VBAndCs
Copy link
Author

VBAndCs commented May 11, 2019

@rskar-git
You are right, and I am OK with your suggestion, and if pattern matching is done with the proposed syntax, its also OK to use it as @zspitz suggested. But I have a third suggestion: We can use =: instead =. In fact I wish if =: was used for assignment everywhere!

With X =: 3

End With

But I am OK with any choice as long as it achieves the goal.

@VBAndCs
Copy link
Author

VBAndCs commented May 11, 2019

On second though:
Why would anyone use With True or With Flase? This is not something to expect to find anywhere to fear to break. So, I think it is safe to use = in with statement for assignment. It is the perfect syntax of all alternatives (except the =: that I like :) )

@pricerc
Copy link

pricerc commented May 12, 2019

If someone who doesn't know much about VB. Or indeed anyone who wasn't closely reading release notes for funky new features saw:

With X =: 3

They would be heading for Google to find out what it means. However, if they saw:

With 3 Into X As Integer

They would be able to figure it out just by reading the statement.

Now; there is a known pattern for :=, which VB uses for named parameters (and what Pascal uses for assignment - we were taught to read it as 'X becomes equal to 3'). So

With X := 3

Would be better.

That just leaves the question about the merits of introducing new punctuation that would require explanation, where a 'wordy' version wouldn't need explaining (I'm not crazy about the actual word 'Into', but I can't think of a better one)

@VBAndCs
Copy link
Author

VBAndCs commented May 12, 2019

With X := 3 Would be better.

Agree. But as I said:

Why would anyone use With True or With Flase? This is not something to expect to find anywhere to fear to break. So, I think it is safe to use = in with statement for assignment. It is the perfect syntax of all alternatives

And also, I feel that pattern matching syntax is too verbose, and seems mirrored!

I may also modify @rskar-git suggestion to be:

Dim X = 3

End Dim

So, Dim statement can have its own block and scope! This is close to inline if statement and block if statement.

But I still prefer:

With X = 3

End With

@sbsdevx
Copy link

sbsdevx commented May 12, 2019

With X = 3 if we want to name it, or see original proposal for pseudo-variable #31

@VBAndCs
Copy link
Author

VBAndCs commented May 12, 2019

@sbsdevx
#437 is close to #31 and both focus on refering to the with object. The perpose here is to have a new local scope for variables outside if, select, for, do and while blocks (I called it a standalone scope in #393 with suggestion to use Let .. End Let but it was rejected then. Declaring a var in the with block can achive both goals: ref the object, and create a new local scobe with a familiar block.

@craigajohnson
Copy link

#437 or similar idea would be great. Most important point for me these many years wanting this change to happen is to be able to avoid declaring a variable name in these cases where the scope of the thing in question is short-lived and the name adds no inherent value to the readability of the block. The "$" proposal, whether or not that is the right identifier, is definitely the idea. Further generalizing to more local scope cases (e.g., Using blocks) also sounds incredibly useful.

@VBAndCs
Copy link
Author

VBAndCs commented May 12, 2019

In fact, I didn't use the with block since 15 years ago at least, exept for the initialization with { }. If the expressions contain only one dot, I use the object directly, otherwise I declare a variable. Merging this declaration with With and giving it a short scope is a benefit for me that will make me reuse With blocks again.

@AdamSpeight2008
Copy link
Contributor

I think := would be better than =: , as would leverage existing knowledge and syntax. That being named argument syntax eg MyMethod( arg0:= 0, arg1:= "Apple")

@AdamSpeight2008
Copy link
Contributor

Personally i am prototyping the allowing of contracting the following form

Using myObj As New DisposableObject()
  With myObj
    .Value = 123
  End With
End Using

into

Using With myObj As New DisposableObject
  .Value = 123
End Using

Don't know if it would be suitable for VB.net, would need to do some analysis on a couple of large repos.

@VBAndCs
Copy link
Author

VBAndCs commented May 12, 2019

@AdamSpeight2008
Agree. But as I said:

Why would anyone use With True or With Flase? This is not something to expect to find anywhere to fear to break. So, I think it is safe to use = in With statement for assignment. It is the perfect syntax of all alternatives

I like your refactoring but what's wrong with this:

Using myObj As New DisposableObject
  .Value = 123
End Using

There is no need for the with keyword! There is risk to break code that have Using nested inside With, but this risk should be calculated to estimate how often this can happen.

@AdamSpeight2008
Copy link
Contributor

Because it currently possible to nest a Using ... End Using inside a With ... End Block the semantics of that can not change. Whereas I am make it explicit that the nearest With block is changing.

@pricerc
Copy link

pricerc commented May 12, 2019

@VBAndCs

Since you've asked this question a few times, I'll try and answer.

Why would anyone use With True or With Flase?

Firstly. "Why would anyone use XXXX?" is my initial response to about 1/2 the suggestions on this forum 😄

I also ask "why would anyone use 'Select Case True' ?", but I know many people like the construct.

But to answer your specific question:
If you had an anonymous With target variable (say, $), then you could use it in logic within the With block. This is a very contrived example (but many on this forum are):

Sub FuBar(snafu as Integer)
   With snafu = 9000
        Call DoFu($)
        If $ Then
             DoBar()
        End IF
    End With
End Sub

The traditional :

Sub FuBar(snafu as Integer)
   Dim IsIt9000 = (snafu = 9000)

   Call DoFu(IsIt9000)
   If IsIt9000 Then
        DoBar()
   End IF
End Sub

Which one looks better and/or more readable, is entirely subjective, but I can see arguments for both.

On your observations about ambiguity:

This is not something to expect to find anywhere to fear to break. So, I think it is safe to use = in With statement for assignment. It is the perfect syntax of all alternatives

It is VERY important that the language be consistent. Just because a particular usage is not expected, that doesn't mean the language should have = get special treatment for just this one (new) scenario; this would make the behaviour of = inconsistent, which is a bad thing, and makes it not perfect syntax.

@VBAndCs
Copy link
Author

VBAndCs commented May 12, 2019

It is VERY important that the language be consistent

It is. = has two meaning, and the language define them. With belongs to the same category as Dim and Using, where = means assignment. There is no meaning to use = for comparison in this context, and I doupt there is a single one had ever done such a thing in the world :)

@pricerc
Copy link

pricerc commented May 13, 2019

It is. = has two meaning, and the language define them. With belongs to the same category as Dim and Using, where = means assignment. There is no meaning to use = for comparison in this context, and I doupt there is a single one had ever done such a thing in the world :)

I don't think your argument around Dim is relevant, because that's a variable declaration, and nothing else. There is no chance of ambiguity.

But your comparison with Using is relevant, because while it's a variable declaration, it is also forms a block definition. A couple of thoughts:

  1. it's different from With because it was a completely new feature being added, and was always designed as a variable declaration, whereas With is not a new feature; we're what we're talking about is a new way of doing and old thing using another old thing.

  2. if Using was applicable to any type of variable, and not just IDisposable objects, and you were able to use an Anonymous variable for the Using block, then we might be having the same conversation about Using.

  3. I gave an example of how someone could use With True using an anonymous reference. While it's not something I would probably do, I don't see that it's any 'stranger' than Select Case True, and I can totally see that someone seeing the construct for the first time might expect to behave that way. I long ago stopped doubting that people do and see strange things with programming languages :)

All those points are not really important, but this one is:
Your suggestion would be a 'breaking' change, as mentioned by @rskar-git , because this is currently legal (even if it's crazy):

Dim x = 1
Dim y = 1

With x = y
	console.writeline("Foo")
End With

@Bill-McC
Copy link

Breaking changes are allowed if they don't do any harm. The issue is about "breaking" ... does it cause damage ?
Assuming Dim is omitted , then With x = y would raise a warning that x is shadowing x from the outer scope. The code will still compile, and the difference would only occur if .ToString was called.
Would the compiler warning on shadowing be enough for this edge case ?

@pricerc
Copy link

pricerc commented May 13, 2019

Breaking changes are allowed if they don't do any harm. The issue is about "breaking" ... does it cause damage ?
Assuming Dim is omitted , then With x = y would raise a warning that x is shadowing x from the outer scope. The code will still compile, and the difference would only occur if .ToString was called.
Would the compiler warning on shadowing be enough for this edge case ?

I'd be really curious to see an example of actual code that uses this construct. It would be code smell to me, but, as I figured out when I wrote up the earlier comment with an attempt at a 'prototype', it doesn't look totally wrong, nor any stranger to me than 'Select Case True', so there could well be someone using it for some weird reason (that I'd love to hear about).

PS: Actually, with the 'anonymous' reference to with With target, it's a more plausible construct than it currently is, in that would allow you to create and use a temporary, nameless boolean.

@VBAndCs
Copy link
Author

VBAndCs commented May 13, 2019

Select Case, If, Do and While statements are conditional statement that you expect to use logical conditins that yield a boolean value. So, Select case True is a statement that can have two branches, and it is a practical yet a bit strabge usage. With on the other hand is a reference stayement, that was important to optimize vb compiler performance before dot net, and shorten the code before successive dots were allowed where nested with statements were needed. Logical boolean comparisons has no place here,and boolean even didn't have any members before dot net, so no legacy code so whaever can use with true/false. So, with can only use = for assignment. Any exsotic code was using it otherwise is not only rare if exists, but also written by someone who really need to learn programming from scratch. So, let's stop defending impossible cases.
As I said and gave more resons here, With statement lost every benefit for me after dotnet, so I stoped using it. Now we can make use of it to achieve extra goals as described. I also want to adjust @AdamSpeight2008 suggestion to be
With Using X As New Foo
.Vlue=123
End With ' Or End With Using

Wtth Using is has a meaning in English but Using with hasn't.

@zspitz
Copy link

zspitz commented May 13, 2019

Wtth Using is has a meaning in English but Using with hasn't.

I'm not sure this is the case. In my opinion, both forms are sufficiently English-like, but neither are really valid English.

@VBAndCs
Copy link
Author

VBAndCs commented May 13, 2019

"Do this with using... " is a regular English stelement. So, you can read the syntax as if it is
With Using something, do
......
End With

Using with is some bit strange and doesn't give a meaning to vb beginners from the fist look, as most vb statements do.

@zspitz
Copy link

zspitz commented May 13, 2019

"Do this with using... " is a regular English stelement.

It is certainly not idiomatic. You might say "Do <x> with <y> using <z>", but with using on its own is equally strange as using with.

@AdamSpeight2008
Copy link
Contributor

I think as my form as the following, Using this Within
The following form is difficult to recognise Using obj As New DisposableObject With as it confilicts with member initializers syntax, which why I discarded it.

@pricerc
Copy link

pricerc commented May 13, 2019

Select case True is a statement that can have two branches

I'm talking about the Select Case True that can have many branches. For example, this is also perfectly 'legal' (if crazy).

Dim x = 1
Dim y = 1
Dim z = 2

Select Case x = y
 Case x * y = z
	console.writeline("Fu")
 Case x - y = z
 	console.writeline("Snafu")
 Case x + y = z
	console.writeline("Bar")	
End Select

Some people like this construct, I don't.

But my point is, that I don't see how With x = y would be any stranger than this, and that I think it would be bad if the semantics were different.

@ericmutta
Copy link

ericmutta commented May 15, 2019

@rskar-git: Perhaps Dim can be of use here?

Dim works great for this scenario and I remember @craigajohnson mentioned it here where we were discussing a larger overall feature: inline variable declarations.

@AdamSpeight2008
Copy link
Contributor

@VBAndCs
Select Case True can have its uses, as it allowed a primitive form of pattern-matching.

Function TryParse_GUID(here As Int32, <Out>ByRef Output As SyntaxNode) As Boolean
 Select Case True
         Case TryParse_GUID_Format_N(Here, Output)
         Case TryParse_GUID_Format_D(Here, Output)
         Case TryParse_GUID_Format_B(Here, Output)
         Case TryParse_GUID_Format_P(Here, Output)
         Case TryParse_GUID_Format_X(Here, Output)
         Case Else
           ' Failure none of the parsing above succeeded.
           Output = Nothing
  End Select
  Return (Output IsNot Nothing)
End Function

@VBAndCs
Copy link
Author

VBAndCs commented May 15, 2019

OK. But threr is no similarity to With, which is a ref block with no more function. Referencing True/False gives access to basic object members, which doesn't worth creating a block, and I doubt anyone ever did that for a practical reason.

@pricerc
Copy link

pricerc commented May 15, 2019

@VBAndCs

I doubt anyone ever did that for a practical reason.

I agree with you.

But In my many years of coding, I've seen many examples of code that doesn't look 'practical' to me. Even some of the examples on this forum have left me scratching my head wondering "Why would anyone do that?"

But I think that it remains a bad reason to make a potentially breaking change to a compiler - just because you and I can't see a practical use for it, doesn't mean someone else hasn't used it for something that we can't think of.

That said, if we had a local, anonymous reference to the With block target, then there are definitely potential uses for it, as I suggested earlier in this thread. Here's a slightly less contrived example (using $ as the 'anonymous' placeholder:

...
   With doc.DocumentType = DocumentType1
        editor1.Enabled = $
        editor2.Enabled = not $
        editor3.Visible = $
        picture1.Visible = $
    End With
...

@craigajohnson
Copy link

Please let's add something to this effect, with no requirement for a variable name. I would use this all the time. Thank you @pricerc and others.

@pricerc
Copy link

pricerc commented May 15, 2019

@craigajohnson , Thanks for your input, but I'm the wrong person to thank, it wasn't my idea!

I'm just here to highlight potential problems, and make sure we get the best VB we can.

@VBAndCs
Copy link
Author

VBAndCs commented May 15, 2019

But I think that it remains a bad reason to make a potentially breaking change to a compiler - just because you and I can't see a practical use for it

Disagree. The cost of fixing such rare blocks doesn't overweight the benefits of the new feature.

That said, if we had a local, anonymous reference to the With block target

This proposal is a replacement for #437 and they can't coexist, so it is not possible to have any anonymous reference other than the var name! So, your code will be:

   With v = (doc.DocumentType = DocumentType1)
        editor1.Enabled = v
        editor2.Enabled = not v
        editor3.Visible = v
        picture1.Visible = v
    End With

The above code is more readable, and allows defining a local scope for var v which can be redefined in other local scopes.

@pricerc
Copy link

pricerc commented May 16, 2019

@VBAndCs.

I don't know why you seem to be trying to prove me wrong. I already said I agree with you!

I was just trying to answer your question, I was not commenting on the merits of the proposal.

You asked why someone would use With <Boolean Test>, so I gave you a potential example that would apply if something like #437 (using $) or #31 Proposal 1 (using .Me instead of $) was adopted.

Furthermore, I don't think your version of my example helps your case:

   With v = (doc.DocumentType = DocumentType1)
        editor1.Enabled = v
        editor2.Enabled = not v
        editor3.Visible = v
        picture1.Visible = v
    End With

Might as well be:

        Dim v = (doc.DocumentType = DocumentType1)
        editor1.Enabled = v
        editor2.Enabled = not v
        editor3.Visible = v
        picture1.Visible = v

If the only way to access the With target was to give it a name, then I wouldn't bother.

Looking at #31 again, I have to say that I think this proposal (#438) is covered by the discussion in #31 (see Proposal 2). As is #437 (in Proposal 1).

Also, as discussed in #31, named and anonymous may be able to coexist if implemented correctly.

If you just want a local block, then create a proposal for that. As I mentioned in #393, Some languages allow arbitrary blocks. maybe something like:

Begin ' local block
         Dim v = (doc.DocumentType = DocumentType1)
         editor1.Enabled = v
         editor2.Enabled = not v
         editor3.Visible = v
         picture1.Visible = v
End ' potentially breaking change, because standalone End means 'End Program'

Note, that if it were up to me, we'd scrap With blocks except for initializers, and then expand using blocks to allow declaration of any type (not just IDisposable), which would be similar to what you're describing . But that's a different discussion.

@VBAndCs
Copy link
Author

VBAndCs commented May 16, 2019

Sorry, but nothing personal I am trying to prove my main point, which using With as a local domain. And I stated with details why I lost interest in With after moving to dot net. Clearly, I will never use $ nor .Me, and if I found such codes in any source I want to reuse, I will replace them. I am not a fan of using too much dots and symbols without any real added value, on the expense of making code less readable and more confusing.
So, I think we have different preferences here, and each of us made his point clear.
Thanks for your concern. I really like arguing with you.

@VBAndCs
Copy link
Author

VBAndCs commented May 16, 2019

If you just want a local block, then create a proposal for that

This was #393, and the team made it clear that they will not add a new scope block #393 (comment) :

We're not going to add a construct for a stand-alone scope.

So, the only possible alternative, is to modify a legacy block to do this job beside its main job. My suggestion adds a bonus of solving the anonymous reference issue, so it can achieve two proposals in one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants