dotnet / vblang

The home for design of the Visual Basic .NET programming language and runtime library.
288 stars 64 forks source link

Proposal: A compact Full ReadOnly Property #403

Open VBAndCs opened 5 years ago

VBAndCs commented 5 years ago

Proposal: A compact Full ReadOnly Property Every time I get confused about the meaning of assigning an expression to auto implemented read-only property in VB: is it just an initial value that is only executed once, or will it be executed every time the property is called?! Public ReadOnly Property Content() as String = Foo() This is becfuase C# has = and => that makes the difference between the two meaning very cler! So, I decide to write the full property:

Public ReadOnly Property Content() string 
   Get
       Return Foo()
   End Get
End Property

I cal recall that there are proposals to add => to VB, but today, I have another suggestion: just get rid of Get… end Get:

Public ReadOnly Property Content() string 
   Return Foo()   
End Property

This shorter syntax has every info that has to tell and still in a VB style (without =>)! And it can be perfect with a multiline body:

Public ReadOnly Property Sum() string 
   Dim _sum = 0
   For each .....
      _sum+= .......
   Next 
   Return _sum   
End Property

Likewise, and just for duality, the write-only property (which I never used) can get rid of the Set End Set and use the Value param directly (as it can be earased from Set End Set today and still be used)

dim _whatEver as string
Public WriteOnly Property WhatEver() As string 
   _whatEver = Value
End Property
AdamSpeight2008 commented 5 years ago

I can't see any issue with allowing this form, as it could be implemented through lowering to the old form internally. If we did that along with single line block methods eg.

Public ReadOnly Property Content() string :  Get :  Return Foo() :  End Get : End Property

So we could then do

Public ReadOnly Property Content() string : Return Foo() : End Property

Which would reduce a lot of "simple" properties to single line implementations.

pricerc commented 5 years ago

While I have sympathy for the goal, I'm not convinced by the argument.

Because I don't see how the use of = is ambiguous in the context of VB.

I get my you might wonder if you're coming from a different language, and you don't yet know VB, but I don't see how in the VB world,

Public ReadOnly Property Content() as String = Foo()

could be read as anything other than Content being assigned the value of Foo().

Would a more VB-esque lambda/expression body style not look more like:

Public ReadOnly Property Content() as String = Get Foo()

?

VBAndCs commented 5 years ago

@pricerc We were forced to read/write a lot of C# codes, so I get confused sometimes here and there! I like: Public ReadOnly Property Content() as String = Get Foo() but this shouldn't prevent

Public ReadOnly Property Content() string 
   Return Foo()   
End Property

This is the spirit that VB built on, you have a semi-natural language, but it is not verbose. Besides. I like using blokes better that break a long singl line into 2 lines. I prefer the single line only when it is short. So, I like to have alternatives. And above all, my suggestion is not only for single line gets. Forgive me if I didn't give a more general sample:

Public ReadOnly Property Sum() string 
   Dim _sum = 0
   For each .....
      _sum+= .......
   Next 
   Return _sum   
End Property

The block above is crying out loud that it is a ReadOnly Property with a body that Returns a value. No confusion here for the compiler nor programmers. It makes me wonder: Why we didn't think of this since 2002? :)

pricerc commented 5 years ago

There are good reasons why object-oriented languages have keywords for things like GETting and SETting properties.

Even C# doesn't allow properties without get/set.

I don't think removing those keywords enhances the language or will makes it easier for people in the future to understand.

What you're proposing reminds me of the old VB6 days, when you'd have:

' Readonly Property
Public Property Get Sum As String
...
End Property

Private m_Name As String
Public Property Get Name As String
    Name = m_Name
End Property

Public Property Let Name(Value As String)
    m_Name = Value
End Property
pricerc commented 5 years ago

If I were to advocate for a change around property declarations, I'd vote for making the ReadOnly and WriteOnly modifiers optional (or inferred) - if there is no Set declared, then it's ReadOnly, if there's no Get declared, then it's WriteOnly.

' ReadOnly property
Property Foo() As String
   Get
     Return GetBar()
  End Get
End Property

Or

' ReadOnly property, Expression body style.
Property Foo() As String = Get Return GetBar()
VBAndCs commented 5 years ago

Another reason: I always fall into this : Public Property ViewName As String = IndexView.CreateNew(Students, ViewData) This property will cause an exception, because it tries to put the initial value IndexView.CreateNew(Students, ViewData) at the construction of the class, where the ViewData is null and using it in the code will cause an exception! this is deferment than: Public Property ViewName As String => IndexView.CreateNew(Students, ViewData) which executes IndexView.CreateNew(Students, ViewData)when the property getter is called! So, I had to write this as:

    Public ReadOnly Property ViewName As String
        Get
            Return IndexView.CreateNew(Students, ViewData)
        End Get
    End Property

Which I should be allowed to be written as:

    Public ReadOnly Property ViewName As String
            Return IndexView.CreateNew(Students, ViewData)
    End Property
VBAndCs commented 5 years ago

And to prove my point, try this:

    Property Test() As Integer = IncValue()

    Dim value = 0

    Function IncValue()
        Return value + 1
    End Function

    Sub Main()
        Console.WriteLine(Test) ' 1 
        Console.WriteLine(Test) ' 1
    End Sub

The Test property will always return 1, because it calls the IncValue only as an intila value, and stuc with this value! the = in the auto implemented properties assigns an initial value, and doesn't declare the property body! This is true even it is a readonly property. So, VB lakes the equivalent of => in C#.

pricerc commented 5 years ago

So, VB lakes the equivalent of => in C#.

This is reasonable observation, one that has been made elsewhere in this repo. There is a whole issue related to expression-body syntax for properties: #61.

If that's your goal, then this proposal is a duplicate of that one.

But apart from that, with respect, the rest of your post just highlights basic 'rookie' mistakes that anyone can make when switching languages (which I also do all the time; I have both C# and VB projects that I'm working on at the moment), and forgetting how the language works. It doesn't mean that it's a problem with the language.

VBAndCs commented 5 years ago

@pricerc The bodied expressions will not cover this:

Public ReadOnly Property Sum() string 
   Dim _sum = 0
   For each .....
      _sum+= .......
   Next 
   Return _sum   
End Property

It doesn't mean that it's a problem with the language.

Surely it is. The language made fatal decision that forced us to use a another language, so it have to make every adjustment to prevent such incompatibility mistakes! VB and C# are living in the same environment, so, they should get rid of confusing mismatchings. This applies also for C# in some syntax cases.

pricerc commented 5 years ago

It doesn't mean that it's a problem with the language.

Surely it is. The language made fatal decision that forced us to use a another language, so it have to make every adjustment to prevent such incompatibility mistakes! VB and C# are living in the same environment, so, they should get rid of confusing mismatchings. This applies also for C# in some syntax cases.

It was not fatal, and I'd suggest to say so is very disparaging of the very, very smart people who have been designing these programming languages for years.

VB and C# are different languages, and the only thing they need to share is the ability to use each other's (compiled) libraries. To put it bluntly: people getting the two confused is not the fault of either language, but of the users of the languages. As my late father always liked to tell me: "A poor workman always blames his tools".

I don't find their 'mismatchings' confusing at all, because I recognise that they are different languages designed with slightly different goals in mind.

@pricerc The bodied expressions will not cover this:

I was responding specifically to your message to prove my point, about VB not having a => construct for an expression bodied syntax. Which I pointed out is covered in #61.

This is something different:

Public ReadOnly Property Sum() string 
   Dim _sum = 0
   For each .....
      _sum+= .......
   Next 
   Return _sum   
End Property

And I don't see the value is this at all. Other than not having to type "Get" (a whole three letters), what is the benefit?

You are actually (as I mentioned earlier), basically advocating a (partial) return to the old VB6 way of declaring properties, and having several subtly different ways of doing the same thing:


' you're proposing:
Public ReadOnly Property Sum() As Double
  Dim result As Double = 0 
' do some stuff
   Return result
End Property

' instead of this, which works fine.
Public ReadOnly Property Sum() As Double
   Get
     Dim result As Double = 0 
   ' do some stuff
      Return result
   End Get
End Property

' and in VB6, it would have been:
Public Property Get Sum() as Double
  Dim result As Double = 0 
' do some stuff
   Sum = result
End Property

There was a conscious decision to move away from the VB6 style, and to put Get and Set into the same Property 'block', and I think that was a good idea. As I mentioned earlier in this thread, I'd support removing the requirement for ReadOnly and WriteOnly (as this can be inferred from the absence of Set or Get), but removing Get/Set..End Get/Set would be a step backwards.

I would also suggest that your proposal (about removing Get/Set..End Get/Set) is contrary to the proposal guidelines laid out in the repo's top-level README ; Under "A good proposal should:".

VBAndCs commented 5 years ago

and to put Get and Set into the same Property 'block', and I think that was a good idea

I don't discuss this idea. It is still applied to read/write properties. I am speaking about unnecessary decorating block. It will not confuse the compiler to erase the Get block in this context. In fact we have erased Get and Set blocks along with the backing field and the compiler get it write! I aim to 2 things here:

  1. Keep the spirit of VB syntax: Nearest to natural language and shortest as possible.
  2. Compact the whole volume of the code file. Modern projects are huge, and even saving one line in a block can save hundreds of lines in the project. Typing less, reading less, and recognize in a glimpse. This should be part of the syntax design goals.
pricerc commented 5 years ago

I aim to 2 things here:

1. Keep the spirit of VB syntax: Nearest to natural language and shortest as possible.

I don't think 'shortest as possible' was ever a design goal for VB

2. Compact the whole volume of the code file. Modern projects are huge, and even saving one line in a block can save hundreds of lines in the project. 

I don't think that is useful on its own, if those lines come at the cost of ease-of-maintenance.

Typing less

I don't think that typing less is a good design goal on its own. Long term maintainability is much more important.

reading less, and recognize in a glimpse.

Maybe, but I'm not sure that you and I will agree on what is easy to recognize in a glimpse.

Which of these do you more quickly recognize as a property, as opposed to a function? (Ideally, you should use a blurred image to try this)

Public Readonly Property FooProp As String
    Get
        Return "BAR"
    End Get
End Property

Public Readonly Property FooProp2 As String
    Return "BAR"
End Property

Public Shared Function FooFunc As String
    Return "BAR"
End Function 

I know which 'Property' I find most obvious.

This should be part of the syntax design goals.

Possibly. But for now, the guidelines are:

A good proposal should:

  • Fit with the general theme and aesthetic of the language.
  • Not introduce subtly alternate syntax for existing features.
  • Add a lot of value for a clear set of users.
  • Not add significantly to the complexity of the language, especially for new users.

I think your proposal falls short on at least three. In particular, it:

In this case, you're advocating for, in addition to the existing property definitions: 1) a new special syntax for ReadOnly properties 2) a new special syntax for WriteOnly properties

I think that adding these two new ways to do something that is already very simple, would have new users asking: "Why do we have three different ways of declaring properties?".

VBAndCs commented 5 years ago

These guidelines can be interpreted in different ways. Most new vb features since 2005 are consedered alternative ways to already existing syntax. Properties and function are distinct keywords. See the real proplem in C# int Map() => Dosomething(); // this is a function int Map => Dosomething((; // this is a property!!

By the way: I always wonder why we need an auto implemented propery with no body, while we can use a public field directly? I asked this 15 years ago, and the answer was becuase properties are needed in binding and other reflection stuff! In fact if this behavior modified to include bublic fields, we will no even write the property keyword!

pricerc commented 5 years ago

I always wonder why we need an auto implemented propery with no body, while we can use a public field directly? I asked this 15 years ago, and the answer was becuase properties are needed in binding and other reflection stuff! In fact if this behavior modified to include bublic fields, we will no even write the property keyword!

Because properties are actually a special set of methods (Property Get is a special kind of Function, and Property Set is a special kind of Sub). The point being that a field does not have code associated with it, but a property does (even if you can't see it)

I'm sure you know that VB just translates auto-implemented properties; from:

Public Property Foo() As String

into

Private _foo As String
Public Property Foo() As String
    Get
        Return _foo
    End Get
    Set(Value As String)
        _foo = Value
    End Set
End Property

C# does much the same, except that it uses a mangled name for the private (backing store) field.

The compiler and runtime are then able to inject code into properties, which they can't do with fields, because fields are just bits of memory, but properties are bits of code.

There's also some basis in object-oriented language design theory, where properties are the preferred interface to the outside world, and fields should really only be private or friend, and never public.

pricerc commented 5 years ago

These guidelines can be interpreted in different ways. Most new vb features since 2005 are consedered alternative ways to already existing syntax.

Possibly, but they're not usually subtle. E.g. Auto-implemented properties are very different from full properties, not just a "subtly alternate syntax".

Properties and function are distinct keywords. See the real proplem in C# int Map() => Dosomething(); // this is a function int Map => Dosomething((; // this is a property!!

Yeah, one of the reasons I'm not a big fan of lambdas and anonymous methods. They look cool, but they can easily cause problems. It's an example of where more typing now helps with maintenance later.

int Map() {
   return DoSomething();
}

int Map { 
    get { return DoSomething(); }
}

is much clearer.

There are also places where using = instead of => won't cause a compiler error, but can cause your program to go wrong.

bandleader commented 5 years ago
  1. For single-expression readonly properties, the better solution is expression-bodied members (#61), which is already in C# (and many other languages).
  2. For properties with multli-line implementations, getting rid of the Get/End Get isn't that great of a gain, and IMHO not a good idea either. However, I would like to point out that the simplest solution for them to get this benefit IMHO is block expressions (#109). This is how every property/method/everything works in Scala and it simplifies things beautifully; there is no need to differentiate between a single-expression and multi-line members, and everything works as well not just for properties/methods, but also for variable declarations, assignments, etc. I'm not sure whether the VB community is willing to think this way, but I don't see why not. Maybe if it gets into C# first... although I don't see a reason we can't be first if the community likes it.