twinbasic / lang-design

Language Design for twinBASIC
MIT License
11 stars 1 forks source link

Support `Option Strict` #5

Open bclothier opened 3 years ago

bclothier commented 3 years ago

Is your feature request related to a problem? Please describe. One major annoyance with VB6 and VBA is that it loves doing magical black magic voodoo implicit conversions and it's not always obvious that a implicit conversion has happened, which could then lead to runtime errors and other bugs that are hard to see during development. In addition there are language features that potentially obfuscate the intention and thus the code ends up not doing what it says it's doing.

Dim SomeAPIResult As Long = 123

If SomeAPIResult = True Then
  'API called successfully
Else
  'Error occurred with calling API
End If

This is obviously wrong but real world code can be more subtle than that and it's not readily apparently that we are comparing 2 different types and thus getting results that we may not expect since the intention was to treat the Long result like a Boolean.

However, the language syntax can also cause problem. For example:

Dim SomeAPIResult As Long = 123

If Not SomeAPIResult Then
  'API called successfully
Else
  'Error occurred with calling API
End If

Again, the intention was to treat it like a Boolean when it is not. Not is not a Boolean operator but a bitwise operator, and thus muddy the water.

Furthermore, because of the implicit conversions it's easy to end up working with Objects or Variant where you were expecting a strong-typed instance. To use Excel's object model:

Worksheets("Sheet1").Name

The .Name is not verified at the compile time because it's bound to an Object even though the user expects it to be an Excel.Worksheet type.

All together, those form a substantial % of runtime errors or bugs arising from the implicit conversions and also thwart effective static code analysis.

Describe the solution you'd like We can replicate the feature offered in VB.NET where specifying Option Strict will disallow implicit conversions. Therefore any expressions that would require implicit conversion should be then highlighted by the compiler as error.

This covers the first example (e.g. SomeLongVariable = True) requiring the user to fix this at compile-time by doing a CBool or changing the expression to SomeLongVariable <> 0 or such).

~I believe the VB.NET's implementation will not cover the 2nd example and 3rd examples. However,~ I'd love to see some way to cover those and thus help manage the misuse of the weak points of BASIC language and encourage correct coding (e.g. prefer If SomeAPIResult Then and If SomeAPIResult = False Then over other variants and the compiler can even suggest it to help encourage good coding habits).

The third case should also convert the expressions such as Worksheets("Sheet1").Name into a compile-time error because we don't know there's a Name method on an Object and thus this is potentially a runtime error. Unfortunately, this is not always possible and we may need to allow such expressions. I do see a immense value in being able to explicitly mark those expressions so it's easy to see where "unsafe" coding is happening and thus manage it accordingly.

~It's possible to cover the 2nd and 3rd case with different keywords (e.g. Option Strict Language? Option Strict Referenceto allow the user to control where/how strict the user wants to be.~

retailcoder commented 3 years ago

I think Option Strict should be implemented as closely as possible to its VB.NET meaning (forbid implicit narrowing conversions and late binding), but to play nicely it should probably come with a proper type cast operator to make it possible to inline explicit type conversions - that said I'm not super-familiar with casting in VB.NET but I believe overloading the As keyword would work for an inline soft-cast (giving it the same meaning as in C# in this context):

Debug.Print (book.Worksheets("Sheet1") As Excel.Worksheet).Name '.Name is early bound
'Expect run-time error 91 if expression isn't an Excel.Worksheet object

The cast could spawn a compile-time diagnostic /warning ("suspicious type cast: expression is never of the specified type" or similar) if the expression isn't Object or Variant, or if the expression's resolved type is early-bound but doesn't implement the specified interface/type.

Alternatively, implement/support whatever casting operator(s) VB.NET supports, otherwise the only way to cast an object to another type is to explicitly assign a reference of that type:

Dim sheet As Excel.Worksheet
Set sheet = book.Worksheets("Sheet1")
'Expect run-time error 13 if RHS isn't a Excel.Worksheet
Debug.Print sheet.Name 'early-bound now
mansellan commented 3 years ago

I've just read this SO answer :- casts in VB.Net use DirectCast(), and the equivalent of C# as is TryCast(). Would this be the preferred syntax here?

mansellan commented 3 years ago

I have to admit though, overloading As has a certain elegance to it, if it doesn't clash with anything else

WaynePhillipsEA commented 3 years ago

As certainly does have an elegance to it... worth considering for sure. Overall I think Option Strict is an important feature to get into tB. Still allowing widening conversions (as per VB.NET) is probably wise though as @retailcoder hinted at ,unless we add a Option Super Duper Strict mode.

mansellan commented 3 years ago

Related because the VB.Net syntax here is inelegant: twinbasic/twinbasic#36