├── .gitattributes ├── CODE-OF-CONDUCT.md ├── Language-Version-History.md ├── README.md ├── meetings ├── 2014 │ ├── LDM-2014-02-10.md │ ├── LDM-2014-02-17.md │ ├── LDM-2014-03-12.md │ ├── LDM-2014-04-01.md │ ├── LDM-2014-04-02.md │ ├── LDM-2014-04-16.md │ ├── LDM-2014-04-23.md │ ├── LDM-2014-07-01.md │ ├── LDM-2014-10-01.md │ ├── LDM-2014-10-08.md │ ├── LDM-2014-10-15.md │ ├── LDM-2014-10-23.md │ └── README.md ├── 2015 │ ├── LDM-2015-01-14-VB.md │ └── README.md ├── 2016 │ ├── LDM-2016-05-06-VB.md │ └── README.md ├── 2017 │ ├── README.md │ ├── vbldm-notes-2017.04.12.md │ ├── vbldm-notes-2017.05.19.md │ ├── vbldm-notes-2017.08.09.md │ ├── vbldm-notes-2017.08.23.md │ ├── vbldm-notes-2017.08.30.md │ ├── vbldm-notes-2017.10.18.md │ ├── vbldm-notes-2017.11.15.md │ └── vbldm-notes-2017.12.06.md ├── 2018 │ ├── README.md │ ├── vbldm-notes-2018.02.07.md │ ├── vbldm-notes-2018.02.21.md │ ├── vbldm-notes-2018.02.28.md │ ├── vbldm-notes-2018.03.21.md │ ├── vbldm-notes-2018.05.30.md │ ├── vbldm-notes-2018.06.13.md │ └── vbldm-notes-2018.12.19.md ├── README.md └── notes-template.md ├── proposals ├── README.md ├── inactive │ └── README.md ├── overload-resolution-priority.md ├── proposal-DerestrictedOperators.md ├── proposal-Implicit-default-optional-parameters.md ├── proposal-template.md └── rejected │ └── README.md └── spec ├── README.md ├── attributes.md ├── conversions.md ├── documentation-comments.md ├── expressions.md ├── general-concepts.md ├── introduction.md ├── lexical-grammar.md ├── overload-resolution.md ├── preprocessing-directives.md ├── source-files-and-namespaces.md ├── statements.md ├── type-members.md └── types.md /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /CODE-OF-CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | This project has adopted the code of conduct defined by the Contributor Covenant 4 | to clarify expected behavior in our community. 5 | 6 | For more information, see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct). 7 | -------------------------------------------------------------------------------- /Language-Version-History.md: -------------------------------------------------------------------------------- 1 | # Features Added in VB Language Versions 2 | 3 | *NOTE:* See how to [specify the language version for your project here](https://docs.microsoft.com/dotnet/visual-basic/language-reference/configure-language-version) 4 | 5 | ## Visual Studio 2022, .NET 6 6 | 7 | - [CallerArgumentExpression](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/caller-argument-expression.md): Note that this feature isn't gated under a language version. It's available for compilers that shipped starting with Visual Studio 2022 version 17.0. 8 | 9 | ## VB 15.0 (Visual Studio 2017) 10 | 11 | - [Tuples](https://github.com/dotnet/roslyn/blob/master/docs/features/tuples.md) 12 | - [Binary Literals](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.0/binary-literals.md) 13 | - [Digit Separators](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.0/digit-separators.md) 14 | 15 | ## VB 15.3 (Visual Studio 2017 version 15.3) 16 | 17 | - [Inferred tuple element names](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.1/infer-tuple-names.md) 18 | 19 | ## VB 15.5 (Visual Studio 2017 version 15.5) 20 | 21 | - [Non-trailing named arguments](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.2/non-trailing-named-arguments.md) 22 | - [Private Protected accessibility](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.2/private-protected.md) 23 | - [Digit separator after base specifier](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.2/leading-separator.md) 24 | 25 | ## VB 17.13 (Visual Studio 2022 version 17.13) 26 | 27 | - Recognizing 'unmanaged' constraint 28 | - [Overload Resolution Priority](https://github.com/dotnet/vblang/blob/main/proposals/overload-resolution-priority.md) 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Visual Basic .NET Language Design 2 | 3 | Welcome to the official repo for Visual Basic .NET language design. 4 | 5 | * Full Language Specification: [Markdown](spec) 6 | * List of proposals can be found in the [proposals folder](proposals). 7 | * Archives of notes from design meetings, etc., can be found in the [meetings folder](meetings). 8 | 9 | If you discover bugs or deficiencies in the above, please leave an issue to raise them, or even better: a pull request to fix them. 10 | 11 | For *new feature proposals*, however, please raise them for [discussion](https://github.com/dotnet/vblang/labels/Discussion), and *only* submit a proposal as a pull request if invited to do so by a member of the Language Design Team (a "champion"). 12 | 13 | ## Discussion 14 | 15 | Discussion pertaining to language features takes place in the form of issues in this repo, under the [Discussion label](https://github.com/dotnet/vblang/labels/Discussion). 16 | 17 | If you want to suggest a feature, discuss current design notes or proposals, etc., please [open a new issue](https://github.com/dotnet/vblang/issues/new), and it will be tagged Discussion. 18 | 19 | GitHub is not ideal for discussions, but it is beneficial to have language features discussed nearby to where the design artifacts are. Comment threads that are short and stay on topic are much more likely to be read. If you leave comment number fifty, chances are that only a few people will read it. To make discussions easier to navigate and benefit from, please observe a few rules of thumb: 20 | 21 | - Discussion should be relevant to Visual Basic .NET language design. Issues that are not will be summarily closed. 22 | - Choose a descriptive title for the issue, that clearly communicates the scope of discussion. 23 | - Stick to the topic of the issue title. If a comment is tangential, start a new issue and link back. 24 | - If a comment goes into detail on a subtopic, also consider starting a new issue and linking back. 25 | - Is your comment useful for others to read, or can it be adequately expressed with an emoji reaction to an existing comment? 26 | 27 | ## Design Process 28 | 29 | Visual Basic .NET is designed by the Visual Basic .NET Language Design Team (LDT). 30 | 31 | 1. To submit, support, and discuss ideas please use the [Discussion label](https://github.com/dotnet/vblang/labels/Discussion). 32 | 33 | 2. Ideas that the LDT feel could potentially make it into the language should be turned into [proposals](proposals), based on this [template](proposals/proposal-template.md), either by members of the LDT or by community members by invitation from the LDT. The lifetime of a proposal is described in [proposals/README.md](proposals/README.md). A good proposal should: 34 | * Fit with the general theme and aesthetic of the language. 35 | * Not introduce subtly alternate syntax for existing features. 36 | * Add a lot of value for a clear set of users. 37 | * Not add significantly to the complexity of the language, especially for new users. 38 | 39 | 3. A prototype owner (who may or may not be proposal owner) should implement a prototype in their own fork of the [Roslyn repo](https://github.com/dotnet/roslyn) and share it with the design team and community for feedback. A prototype must meet the following bar: 40 | * Parsing (if applicable) should be resilient to experimentation--typing should not cause crashes. 41 | * Include minimal tests demonstrating the feature at work end-to-end. 42 | * Include minimal IDE support (keyword coloring, formatting, completion). 43 | 44 | 4. Once a prototype has proven out the proposal and the proposal has been _approved-in-principle_ by the design team, a feature owner (who may or may not be proposal or prototype owner(s)) implemented in a feature branch of the [Roslyn repo](https://github.com/dotnet/roslyn). The bar for implementation quality can be found [here](https://github.com/dotnet/roslyn). 45 | 46 | 5. Design changes during the proposal or feature implementation phase should be fed back into the original proposal as a PR describing the nature of the change and the rationale. 47 | 48 | 6. A PR should be submitted amending the formal language specification with the new feature or behavior. 49 | 50 | 7. Once a feature is implemented and merged into shipping branch of Roslyn and the appropriate changes merged into the language specification, the proposal should be archived under a folder corresponding to the version of the language in which it was included, e.g. [VB 15.1 proposals](proposals/adopted/vb15.1)). Rejected proposals are archived under the [rejected folder](proposals/rejected). 51 | 52 | ## Language Design Meetings 53 | 54 | Language Design Meetings (LDMs) are held by the LDT and occasional invited guests, and are documented in Design Meeting Notes in the [meetings](meetings) folder, organized in folders by year. The lifetime of a design meeting note is described in [meetings/README.md](meetings/README.md). LDMs are where decisions about future Visual Basic .NET versions are made, including which proposals do work on, how to evolve the proposals, and whether and when to adopt them. 55 | 56 | ## Implementation 57 | 58 | The reference implementation of the Visual Basic .NET language can be found in the [Roslyn repository](https://github.com/dotnet/roslyn). Until recently, that was also where language design artifacts were tracked. Please allow a little time as we move over active proposals. 59 | 60 | **DISCLAIMER**: An active proposal is under active consideration for inclusion into a future version of the Visual Basic .NET programming language but is not in any way guaranteed to ultimately be included in the next or any version of the language. A proposal may be postponed or rejected at any time during any phase of the above process based on feedback from the design team, community, code reviewers, or testing. 61 | -------------------------------------------------------------------------------- /meetings/2014/LDM-2014-02-10.md: -------------------------------------------------------------------------------- 1 | VB Language Design Meeting 2014-02-10 2 | 3 | # Strict Module 4 | 5 | C# lets you have "static class" but VB only has "Module" which lifts all its members into the namespace. Discussion on this was prompted by a comment of MVP Jan Záruba (Đonny) who said 6 | > I use Partial Private Sub New to achieve the same effect as in C# with static class. The advantage of this compared to Module is that static class does not "pollute" namespaces with it's members (and I also cannot have generic module anyway)." 7 | 8 | Đonny encountered a known and approved Roslyn breaking change, where VS2013 let you write "private partial sub new", but Roslyn doesn't. This is by design. But the question is, what could he and other users do? 9 | 10 | Language designer Anthony D. Green looked into it: 11 | > Today VB’s modules behave very much like F#’s modules when the AutoOpen attribute is applied. I’m proposing adding a modifier “Explicit” to modules which will go the other way. Additionally, we’d considered changing the codegen of VB Modules to exactly match those of C# (both abstract and sealed) so that they could be recognized by C# in Dev10. Unfortunately this turned out to be a breaking change due to a bug in the XmlSerializer. With my proposal we could consider changing the metadata representation to match C# and could also map C# static classes back to Explicit Modules. If C# does end up accepting the static import feature but retains the restriction to static classes it’ll be important to have a way for VB code to easily create such things – otherwise C# won’t be able to consume them (e.g. the Roslyn VB SyntaxFactory module). 12 | 13 | ## IL 14 | 15 | C# static classes are currently emitted as `.class private abstract auto ansi sealed beforefieldinit` 16 | VB modules are currently emitted as `[StandardModule] .class private auto ansi sealed` 17 | 18 | ## Language design 19 | 20 | * How do you declare something whose name is hidden and whose members are lifted to the enclosing namespace? 21 | ** VB: 22 | ** C#: not available 23 | ** F#: not available 24 | * How do you declare something where people have to qualify member access, unless they specifically import them all? 25 | ** VB: **NOT POSSIBLE, BUT DESIRABLE** 26 | ** C#: new C#/Roslyn feature, "static usings" 27 | ** F#: this is the default 28 | * How do you declare something which *always* requires qualification to access members? 29 | ** VB: not available 30 | ** C#: this is the default 31 | ** F#: [] 32 | 33 | There's a clear VB parity gap here, which has been asked-for many times on user-voice and connect. 34 | 35 | Anthony's proposal is for "static classes", no more, no less. The question is (1) whether to allow it, (2) whether to call it "explicit module" or "shared class" or something. 36 | 37 | RESOLUTION: yes, we should allow it. 38 | 39 | ## Syntax 40 | 41 | We need a new keyword or keyword pair. Here are the candidates we came up with. 42 | 43 | **Strict Module** 44 | MustQualify Module 45 | Explicit Module 46 | Opaque Module 47 | MustQualifyMember Module 48 | Closed Module 49 | Protected Module 50 | Private Module 51 | Static Module 52 | Greedy Module 53 | Shared Module 54 | Shared Class 55 | Namespace Module 56 | 57 | RESOLUTION: We'll use "strict module" as the best of a bad bunch. We're open to suggestions for better names. 58 | 59 | ## Semantics 60 | 61 | The metadata we emit for "Strict Module" should be the same as the metadata for C# static classes. 62 | 63 | Q. Generics? We could say "strict modules" can be generic. Note: you also can't have generic modules in VB. 64 | RESOLUTION: Strict modules CAN be generic; however generic modules CANNOT contain extension methods. 65 | 66 | Q. Nesting? Currently VB modules can't be nested. C# static classes can be nested. 67 | RESOLUTION: Strict modules cannot be nested. 68 | 69 | Q. For C#/Roslyn new feature, when they import static types, will they also allow importing VB modules? 70 | RESOLUTION: up to C# 71 | 72 | Q. How about VB importing C# static classes? 73 | RESOLUTION: Currently, VB can import C#'s static classes, and if they come with [StandardModule] then we auto-open. We will continue to do this. NOTE: THIS IS A BREAKING CHANGE: e.g. you will no longer be able to declare variables of type "Console". Doesn't seem a very bad breaking change. 74 | 75 | Q. What about ? 76 | A. Intellisense will ignore this attribute on strict modules. 77 | -------------------------------------------------------------------------------- /meetings/2014/LDM-2014-03-12.md: -------------------------------------------------------------------------------- 1 | # ProtectedAndFriend, ProtectedOrFriend 2 | 3 | ## BACKGROUND 4 | 5 | The CLI includes two access modifiers "FamilyAndAssembly" (which allows access to derived types that are in the same assembly) and "FamilyOrAssembly" (which allows access to types if they are derived, and also allows access to types if they are in the same assembly). The concepts are explained well here: http://stackoverflow.com/questions/22856215/what-is-the-meaning-of-the-planned-private-protected-c-sharp-access-modifier 6 | 7 | ## REQUEST 8 | VB and C# already have syntax for FamilyOrAssembly ("Protected Friend"). Please add syntax to allow VB to express FamilyAndAssembly. 9 | 10 | ## RESOLUTION 11 | VB will add two new access modifiers, which are exact transliterations of the CLI keywords... 12 | 13 | ``` vb 14 | ProtectedAndFriend 15 | ProtectedOrFriend 16 | ``` 17 | 18 | The pretty-lister will not turn "Protected Friend" into "ProtectedOrFriend". However, if the user types "private protected" (or whatever syntax C# chooses) then it will pretty-list the entire file into C#. JOKE. No it won't. But it may pretty-list the C# syntax into "ProtectedAndFriend". 19 | 20 | Here are some code samples: 21 | 22 | ``` vb 23 | ProtectedAndFriend Sub f() 24 | 25 | Friend Property p As T 26 | Get 27 | Protected Set 28 | ' means anyone in the assembly can see it, 29 | ' but only those who also derive can set it 30 | End Property 31 | 32 | Protected Property p As T 33 | Get 34 | Friend Set 35 | ' means it's a protected property, but 36 | ' only my assembly can set it 37 | End Property 38 | ``` 39 | 40 | ## DISCUSSION 41 | Alex wrote, "Around Private Protected, I really feel like we make a mistake if we choose our VB syntax with the arbitrary choice that C# made so that it could look like C++. We should embrace this as one of those times where VB’s trend towards verbosity leads naturally to a design whose meaning is obvious at first glance. We don’t want to get stuck in a design rut where we’re OK with C# being clearer than VB where terseness pays off, but not vice versa where verbosity pays off – by definition, then, VB will always be less clear than C#." 42 | 43 | Neal observed that the sense of "And/Or" is confusing. It might be a logical And of the permissions, or a logical And of the restrictions. Nevertheless, the CLI has chosen a canonical sense, and we're copying it. 44 | 45 | ## OTHER DESIGNS CONSIDERED 46 | 47 | ``` c# 48 | private protected 49 | protected if internal 50 | internal && protected // also "internal || protected" 51 | internal and protected // also "internal or protected" 52 | internalAndProtected // also "internalOrProtected" 53 | ``` 54 | ``` vb 55 | ProtectedAndFriend ' also "ProtectedOrFriend" 56 | Protected And Friend ' also "Protected Or Friend" 57 | ProtectedFriend ' rejected because it's just one space away from "Protected Friend" 58 | FamilyAndAssembly ' also "FamilyOrAssembly" 59 | Private Protected 60 | Protected OnlyIn Friend 61 | Protected But Friend 62 | Protected If Friend 63 | Protected When Friend 64 | Protected Xor Friend ' just a joke... :) 65 | ``` 66 | 67 | 68 | # Faster CInt(Double) 69 | 70 | ## Background 71 | 72 | ``` c# 73 | double d = 10.5; 74 | int x = (int)d; 75 | ``` 76 | ``` vb 77 | Dim x = CInt(d) 78 | ``` 79 | 80 | The VB version is slower than C#. Indeed, any time we call CInt, the compiler always codegens a call to Math.Round. Even CInt(Math.Round(x)) gets compiled into Math.Round(Math.Round(x)). 81 | 82 | ## Request 83 | Please allow us to write fast integer casts in VB. 84 | 85 | ## Resolution 86 | 87 | **Part 1**: Any time the compiler generates an implicit call to Math.Round (i.e. as part of `CInt, CLong, CULong, CUint`), and if the argument of that implicit call is one of a list of math functions known to return a whole number, then omit the outer call to Math.Round. The list of known math functions is: `Round(d), Round(d,MidpointRounding), Truncate(d), Floor(d), Ceiling(d), VisualBasic.Fix(d), VisualBasic.Int(d)`. 88 | 89 | 90 | **Part 2**: If the user writes `CInt(Math.Truncate(d))` then we will emit `conv.i4` or `conv.ovf.i4` dependent on the current project-level "check-overflow" settings. (TODO: verify that `conv.i4` has exact same semantics as `CInt(Math.Truncate)`, including negative values, superlarge doubles and exceptions, NaN, Infinity). Also do likewise for `conv.i1, conv.i2, conv.i4, conv.i8` and for their unsigned versions, and for both checked and unchecked versions. 91 | 92 | 93 | ## Discussion 94 | 95 | This is a compiler optimization, pure and simple. It adds no new syntax or concepts or library functions. We identify targeted scenarios and generate optimal IL in those cases where semantics would not be affected. This seemed the cleanest approach. Specifically, it seemed better than adding any of the following syntaxes: 96 | ``` vb 97 | DirectCast(d, Integer) 98 | (Integer)d 99 | VB.FastCast(d) 100 | d As Integer 101 | ``` 102 | 103 | Will it be better to special-case just one of these combinations? e.g. conv.i4 on CInt(Truncate(double))? Or is it better to just do all of them? Default answer: "yes do all of them", and only scale back if the compiler-dev comes back and says it's too hard. 104 | 105 | There are other possible concerns, e.g. what happens if it turns out that the semantics of conv.i4 are actually different from ALL of the Math.Round-like functions? What if it turns out that it's really hard to implement every case? What if expression-trees throw a wrench in the works? Well, when devs set about implementing the feature, then we can come back to check. 106 | 107 | -------------------------------------------------------------------------------- /meetings/2014/LDM-2014-04-01.md: -------------------------------------------------------------------------------- 1 | # Null propagating operator ?. 2 | 3 | The `?.` operator is the second-highest voted request on UserVoice 4 | http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/3990187-add-operator-to-c 5 | 6 | We've discussed it in C# and VB Language Design Meeting. Mads has written up detailed notes [here](https://roslyn.codeplex.com/discussions/540281) and [here](https://roslyn.codeplex.com/discussions/540514). Some questions still remain, so I'm starting a thread for general discussion of this feature. 7 | 8 | The core idea is to save you having to write code like this all the time, with null-checks: 9 | ``` cs 10 | var temp = GetCustomer(); 11 | string name = (temp == null) ? null : temp.name; 12 | ``` 13 | 14 | Instead you'd write this: 15 | ``` cs 16 | var temp = GetCustomer()?.name; 17 | ``` 18 | 19 | ## How does ?. behave in sequences? 20 | 21 | Q. How does it behave if you have several of these things in sequence? There are two possibilities on the table: 22 | * *Left-associative* 23 | * *Right-associative* 24 | 25 | 26 | 27 | ``` cs 28 | class Customer1 29 | { 30 | public readonly ExtraRef extraRef = new ExtraRef(); 31 | } 32 | 33 | class ExtraRef 34 | { 35 | public readonly string name = "fred"; 36 | } 37 | 38 | Customer1 GetCustomer1() 39 | { 40 | return (RND.Next() > 0.5) ? null : new Customer1(); 41 | } 42 | 43 | int? len1a = GetCustomer1()?.extraRef?.name?.Length; 44 | int? len1b = GetCustomer1()?.extraRef.name.Length; 45 | ``` 46 | 47 | What do you expect about `len1a` and `len1b`? [**edit** - initially I wrote the following out wrong. I've fixed them.] 48 | 49 | * len1a - this is the same for both *left-associative* and *right-associative* -- it performs a null-check on GetCustomer1(), and if that succeeds, then it will perform null-check on extraRef and name. 50 | * len1b - under *left-associative* it is a **compile-time error**. But under right-associative, it performs a null-check on GetCustomer1(), and then **skips** the null-check on extraRef and name. 51 | 52 | Note: I constructed this example so that, if GetCustomer1() returns non-null, then I as the programmer know (from readonliness) that extraRef and name will both be non-null. The question is, is there some way to communicate this fact to the compiler, to avoid superfluous null-checks? **Left-associative says there isn't; right-associative says there is.** 53 | 54 | (I benchmarked about a 5% perf overhead of doing those extra null-checks in the case where GetCustomer1() returns non-null) 55 | 56 | 57 | ``` cs 58 | class Customer2 59 | { 60 | public readonly ExtraStruct extraStruct = new ExtraStruct {age=29}; 61 | } 62 | 63 | struct ExtraStruct 64 | { 65 | public int age; 66 | } 67 | 68 | Customer2 GetCustomer2() 69 | { 70 | return (RND.Next() > 0.5) ? null : new Customer2(); 71 | } 72 | 73 | int? age2a = GetCustomer2()?.extraStruct?.age; 74 | int? age2b = GetCustomer2()?.extraStruct.age; 75 | ``` 76 | 77 | What do you expect about `age2a` and `age2b` ? 78 | 79 | * age2a (how you must write it under *left-associative*) - this performs a null-check on GetCustomer2() and if this succeeds then, thanks to **compiler-optimization** and despite what's written, it knows it can skip the null-check on extraStruct. 80 | * age2b (how you must write it under *right-associative*) - this performs a null-check on GetCustomer2() and if this succeeds then, **because of how you wrote it**, it skips the null-check on extraStruct. 81 | 82 | Here, extraStruct is a structure and can never be null. So it doesn't make sense to null-check it. Should this fact be expressed as a compiler optimization in `age2a`? Or should it be expressed in syntax in `age2b`? 83 | 84 | 85 | ``` cs 86 | var x = GetCustomer1()?.extraRef?.name?.Length 87 | ==> 88 | var explainingVariable = GetCustomer1()?.extraRef; 89 | var x = explainingVariable?.name?.Length; 90 | ``` 91 | 92 | * Is this a valid refactoring? 93 | * *left-associative* : it is a valid refactoring 94 | * *right-associative* : it's an invalid refactoring 95 | * How would you add parentheses to make the order explicit? 96 | * *left-associative* : `x = ((GetCustomer1()?.extraRef)?.name)?.Length` 97 | * *right-associative* : `x = GetCustomer1()?.(extraRef?.(name?.Length))` 98 | 99 | You can see why we call them left-associative vs right-associative. It has to do with how you'd put parentheses into the expressions if you were writing them out explicitly. 100 | 101 | Incidentally, there are other places where you can't just introduce an explaining variable. For instance, in `var y = a * b + c * d`, you can't just introduce an explaining variable for the first three parts `var ev = a * b + c; var y = ev * d;`. In this case though it's because of precedence, not because of associativity. 102 | 103 | [NOTE: that + is meant to be a PLUS sign. I don't know what's up with the markdown...] 104 | 105 | Eric Lippert wrote a great blog on the associativity of the ?? operator: http://blog.coverity.com/2013/10/23/null-coalescing-bugs/#.Uzurzo1OV3Q 106 | 107 | 108 | ## Some other idioms with ?. 109 | 110 | ``` cs 111 | // Call Dispose only if x is non-null: 112 | x?.Dispose(); 113 | 114 | 115 | // Trigger an event only if it's non-null 116 | // (not needed in VB, since this is already built into RaiseEvent statement) 117 | event EventHandler OnFired; 118 | void Fire() 119 | { 120 | OnFired?.Invoke(this, new EventArgs()); 121 | } 122 | ``` 123 | 124 | 125 | ## Codegen for ?. 126 | 127 | I asked some CLR experts about what assembly code would be generated by the JIT for the ?. operator, and filled in some details from my hazy memory of OS architecture... 128 | 129 | The question was, where does NullReferenceException currently get generated? When you do `GetCustomer1().extraRef`, and GetCustomer1() happens to return null, and so it fires a NullReferenceException, does that happen because the JIT implicitly generates a null-check? 130 | 131 | No. The answer is that the NullReferenceException is generated at a lower level. More specifically, in between CPU and RAM there’s a chip called "Memory Management Unit (MMU) / Page Table". Every single time a thread accesses an address in the process’s virtual address-space, the MMU looks up the address in that page table to find where the address is in physical memory. If the virtual address isn’t yet mapped to a page of memory, then the MMU generates a page-fault which the OS has to handle, e.g. by paging in from disk. The CLR reserves addresses at the bottom of virtual address space but never actually pages them in. If ever an instruction tries to look up any address there, then the MMU generates a fault, and the CLR responds to it by generating a NullReferenceException. 132 | 133 | The codegen for `x?.y` would probably be something like this... 134 | ``` 135 | mov rax, X 136 | test rax, rax 137 | beq :lbl 138 | mov rax, [rax + k] 139 | :lbl 140 | ``` 141 | 142 | [Note: that + is meant to be a PLUS sign. I don't know what's up with the markdown...] 143 | 144 | 145 | -------------------------------------------------------------------------------- /meetings/2014/LDM-2014-04-16.md: -------------------------------------------------------------------------------- 1 | # #Warning Disable 2 | 3 | ## REQUEST 4 | 5 | Please add `#pragma` to VB so we can suppress warnings. This will be especially useful for Roslyn Diagnostics, where people will find many more warnings in their code. 6 | 7 | ## RESOLUTION 8 | 9 | Add two new preprocessor directives: 10 | 11 | ``` vb 12 | #Disable Warning 40008, BC42358, "BC42356" 13 | #Enable Warning 40008, BC42358, "BC42356" 14 | ``` 15 | 16 | ## ALTERNATIVE SYNTAXES CONSIDERED 17 | 18 | ``` vb 19 | #pragma disable 20 | #pragma enable 21 | 22 | #Disable ' sounds like you're disabling code, not warnings 23 | #Enable 24 | 25 | #Ignore 26 | #End Ignore ' block structure is worse than toggles 27 | 28 | #Disable Warning 29 | #Enable Warning 30 | ``` 31 | 32 | 33 | ## DISCUSSION 34 | 35 | The tradition in VB and its rich history of quick-fixes is that you resolve warnings by FIXING YOUR CODE, e.g. by doing whatever the quickfix says, adding an explicit cast, adding a return statement, ... 36 | 37 | Q. Do people really use #pragma much in C# today? Hard to say. With new Roslyn diagnostics, will *more* people start using #pragma in C# ? Will people write Roslyn diagnostics that have a much higher false-positive rate than existing rules, for people who wish to be more careful, safe in the knowledge that it's easy to suppress? 38 | 39 | Q. Is there a downside to adding #pragma to VB for suppressing warnings? - no, not really 40 | 41 | Q. Should we add a feature which suppresses the warning merely for the next line, rather than for the rest of the file? -- This isn't feasible in C# where lines don't really exist semantically. It is feasible for VB. Disadvantage: would confusing for LINQ, and not refactoring-safe. Advantage: if the lightbulb/quickfix appears for a warning, and when you chose the option to "suppress warning" then it only has to insert a single line to "suppress-warning-on-next-line", rther than having to insert `#ignore` before and `#restore` after. Conclusion: No we won't add this next-line-suppression feature. 42 | 43 | Q. Is it good to disable/enable on a "block" basis like `#Ignore / #End Ignore` ? Or on a toggle basis like `#Disable Warning / #Enable Warning` ? Well, with blocks you can't do overlapping regions. And you can't easily disable warnings for an entire method but then re-enable them for a small critical region inside (even though that's a weird scenario). We believe overall that toggles are nicer. They have a lot of engineering, thought and experience behind them. 44 | 45 | Q. For the ``, should quotation marks be obligatory? - No. You can use any identifier or integer. It's only if the warning-id has spaces or other weird characters that you'd need quotation marks. 46 | 47 | Q. Should we allow pure integers for the ``, with the expectation that they disable intrinsic VB compiler warnings? All user-defined warnings (that come through Roslyn diagnostics) would have error codes that aren't pure integers. -- Yes, let's allow integers, just like C#, and just like the VB command-line. It will be a common case. 48 | 49 | Q. Will the Roslyn diagnostics APIs allow people to define error codes that are just pure numbers, even though they'll be impossible to disable them? -- No real need. Diagnostic-authors will learn soon enough not to do this. 50 | 51 | Q. Should we allow you to disable/enable command-separated lists of warnings in a single `#Disable Warning / #Enable Warning` directive? -- Yes. 52 | 53 | Q. Preprocessor directives look ugly because they're always left-aligned. Can we make it so preprocessor directives can be indented? There's a uservoice request for it. -- Not discussed; left for another day. 54 | 55 | 56 | # Back-compat break with interface implementations 57 | 58 | We also discussed another topic to do with ambiguity between unrelated interfaces. Discussion is in this thread: 59 | https://roslyn.codeplex.com/discussions/570975 60 | 61 | 62 | # Update: VB LDM 2014.07.01 63 | 64 | We re-visited #Disable Warning. The summary for VB is: 65 | 66 | * Use the syntax `#Disable Warning id1, id2, ...` 67 | * The warning IDs must parse as per the same rules of VB identifiers, and are case-insensitive. That rules out plain numbers `#Disable Warning 4008` (instead you must disable BC4008) and it rules out strings `#Disable Warning "Don't Use Capitals!"`. That means you can't disable warnings that have fancy error codes with punctuation and so on. 68 | * This will guide users to the thought that they can right-click, find all references, and opens up the mental door to other refactorings/tooling 69 | * We will restrict what identifiers can be produced at the production side too, when authoring analyzers 70 | * We used to give BC2026 “that warning can’t be configured” when you try to nowarn or warnaserror on non-existent warnings (and also on certain named warnings e.g. 2026). But that wouldn’t work for diagnostic warning codes. So let’s no longer emit BC2026 ever. Instead, if you try to disable or enable a non-existing warning, simply do nothing. 71 | * Stretch goal: the IDE could grey out all identifiers that have been disabled but are never actually generated by the code 72 | 73 | C# will be mostly similar, but 74 | * C# will support disabling warnings/errors by number as well as by identifier, and is case sensitive. It has to support disabling numbers for back-compat. If you disable warning number 4008, that's equivalent to disabling identifier CS4008. 75 | * As with VB, we stop validating whether the warning code is a legal compiler warning ID (both on the command-line and inside #pragma) - CS1691 will no longer be reported for C#. 76 | 77 | Things that fall out for free: 78 | * No changes required to disallow Hexadecimal, Octal, Long etc. literals 79 | * No need to worry about making BC2026 unerrorable 80 | 81 | For the future: 82 | * Update lightbulb suppression to always generate #pragma / #disable with identifiers. (Do we need to check that the id will be a legal identifier before spitting the code?) 83 | * Fix /nowarn and /warnaserror command-line switches to support custom diagnostics 84 | * Implement grey out for “unused” ids in #pragma, #Disable (plus corresponding code fix) 85 | * Have some way for users to get from a reported warning id / from a warning id used in #pragma or #Disable to a description of the diagnostic 86 | * Support for qualified identifiers that use dots (only if customers ask for it) 87 | 88 | -------------------------------------------------------------------------------- /meetings/2014/LDM-2014-04-23.md: -------------------------------------------------------------------------------- 1 | (this discussion happened in VB language design meeting, but it strongly concerns C# also). 2 | 3 | 4 | # Better support for immutable data, with pattern-matching 5 | 6 | ## Request 7 | 8 | Please make it easier for me to declare immutable data-types, and make it easier to code over them via pattern-matching. Easier immutable datatypes will make my code have fewer defects, and pattern-matching over immutable data (like in F#, Scala and other functional languages) will allow clean readable maintanable coding idioms. 9 | 10 | For instance, I have a method and want to return 2-3 return values. Here's the ugly code I write now: 11 | ``` cs 12 | // Ugly 1: use out params (but doesn't work with async) 13 | void Lookup(out string name, out int x, out int y) {...} 14 | ... 15 | Lookup(out name, out x, out y); Console.WriteLine(name); 16 | 17 | 18 | // Ugly 2: use a tuple (but my consumer has a hard time knowing which element is what) 19 | Tuple Lookup() {...} 20 | ... 21 | var r = Lookup(); Console.WriteLine(r.Item1); 22 | 23 | 24 | // Ugly 3: declare a custom datatype 25 | class LookupResult(string name, int x, int y) 26 | { 27 | public string Name {get;} = name; 28 | public int X {get;} = x; 29 | public int Y {get;} = y; 30 | } 31 | LookupResult Lookup() {...} 32 | ... 33 | var r = Lookup(); Console.WriteLine(r.Name); 34 | ``` 35 | 36 | What I'd like is to write all this much more simply: 37 | ``` cs 38 | class LookupResult(string name, int x, int y); 39 | LookupResult Lookup() {...} 40 | 41 | var r = Lookup(); Console.WriteLine(r?.name); 42 | ``` 43 | 44 | Even better, I'd like to deconstruct the returned value using pattern-matching: 45 | ``` cs 46 | if (Lookup() matches LookupResult(var name, var x, var y)) { ... } 47 | ``` 48 | 49 | 50 | ## Background 51 | 52 | We have been guided in our thoughts by the paper "Matching Objects with Patterns" by Emir, Odersky and Williams. There's a link to it on this Scala webpage: http://www.scala-lang.org/old/node/112 53 | 54 | The Roslyn compiler currently has "primary constructors" in C#, and a form of "typecase" in VB: 55 | 56 | ``` cs 57 | class C(int x, int y) 58 | { 59 | public int X { get; set; } = x; 60 | public int Y { get; set; } = y; 61 | } 62 | ``` 63 | ``` vb 64 | Function GetArea(shape As Shape) As Double 65 | Select Case shape 66 | Case r As Rect : Return r.X * r.Y 67 | Case c As Circle : Return Math.PI * c.Radius * c.Radius 68 | End Select 69 | End Function 70 | 71 | ' Once we add Out expressions to VB, you can get more pattern-matchey 72 | Function Eval(expr As Expr) As Integer 73 | Select Case expr 74 | Case e As PlusExpr When e.Matches(0, Out rhs) 75 | Return Eval(rhs) 76 | Case e As PlusExpr When e.Matches(Out rhs, 0) 77 | Return Eval(rhs) 78 | Case e As PlusExpr When e.Matches(Out lhs, Out rhs) 79 | Return Eval(lhs) + Eval(rhs) 80 | Case e As IntExpr 81 | Return e.Val 82 | End Select 83 | End Function 84 | ``` 85 | 86 | **Question: how will the two features work together?** Will there be a "sweet spot" where their designs mesh together well, and mesh with additional features in future versions of the languages, to produce a nice pattern-matching design? Something as nice as what F# or Scala have? 87 | 88 | **Urgent question: do we need to make changes to the CURRENT design of primary constructors and Select Case** so that we don't block off a future world of pattern-matching? 89 | 90 | 91 | ## PROPOSAL: Records, and Plain Old CLR Objects 92 | 93 | Here is a coherent set of proposals that combine construction and deconstruction into one neat easily-written proposal, to support the scenario in the "Request". 94 | 95 | 96 | Imagine something called a *"Record"*, a type with an ordered list of named data members. Not saying there should be a new kind of type called a "record type" alongside classes and structs... indeed it might be best not to have a new kind of type, since we might want record-like classes and structs. 97 | 98 | **PROPOSAL 1:** a record can be defined using primary-constructor syntax, and it is syntactic sugar for an expanded form as follows... 99 | ``` cs 100 | class Point(int X, int Y); 101 | 102 | ==> 103 | 104 | class Point(int X, int Y) 105 | { 106 | public int X { get; } = X; 107 | public int Y { get; } = Y; 108 | } 109 | ``` 110 | 111 | The rule is: "When you write a record, it automatically generates properties for the *PRIMARY PROPERTIES*, unless you have provided those properties yourself". The term "Primary Properties" refers to the parameters in the primary-constructor syntax. Thus, if you didn't want it to auto-generate a property, you'd have to provide your own version of that property, as in the example below. (There's no way to say that you *don't* want the property with this syntax: if you don't want the property, then don't use the feature at all). 112 | ```cs 113 | class Point(int X, int Y) { public int X => 15; } 114 | 115 | ==> 116 | 117 | class Point(int X, int Y) 118 | { 119 | public int X => 15; 120 | public int Y {get; set;} = Y; 121 | } 122 | ``` 123 | 124 | **PROPOSAL 2:** Just as we've seen the compiler auto-generate properties if you failed to provide them yourself, it will also auto-generate a default implementation of Equals and GetHashCode if you fail to provide them yourself. This default implementation will do element-wise calls to Equals and GetHashCode on the primary properties. 125 | 126 | (By default, Proposal 1 uses immutable properties, and so Equals/GetHashCode will terminate. It's bad practice to for GetHashCode to calculate based on mutable properties.) 127 | 128 | 129 | **PROPOSAL 3:** In addition to auto-generated properties, Equals, GetHashCode, we also auto-generate a MAtch operator (unless one is provided by the user)... 130 | 131 | ``` cs 132 | class Point(int X, int Y) 133 | { 134 | public int X {get;} = X; 135 | public int Y {get;} = Y; 136 | public static bool operator Matches(Point self, out int X, out int Y) {X=self.X; Y=self.Y; return true;} 137 | } 138 | ``` 139 | 140 | In addition to this, we introduce a new *MATCH* operator into the language: 141 | 142 | ``` cs 143 | matches T(args) 144 | ``` 145 | Operational semantics: 146 | 147 | 1. Evaluate "var tmp1 = " 148 | 2. Look in type "T" for an overload of "Matches" whose 2nd...last parameters match the arguments 149 | 3. Evaluate "var tmp2 = tmp1 As TFirst" where TFirst is the type of the first parameter of that overload 150 | 4. If this is null, then the match operator returns false 151 | 5. Otherwise, the result invoke the Match operator, passing it (tmp2, args) as arguments. 152 | 153 | You'd use the match operator like this: 154 | ``` cs 155 | if (f() matches T(var name, var x, var y)) { ... } 156 | ``` 157 | Note that this would have different rules from the way out vars are currently conceived. These out be definitely assigned only if the "e matches T(args)" returns true. Incidentally, note that the T's Match operator is not necessarily invoked... e.g. if f() returns null, then it won't be called! 158 | 159 | 160 | 161 | **PROPOSAL 4:** You could also treat the typename as a method, e.g. 162 | ``` cs 163 | var p = Point(2,3); 164 | ==> 165 | var p = new Point(2,3); 166 | ``` 167 | All this does is remove the need for the word "new" for these record types. It might seem pointless, but it unifies the way you write construction and deconstruction... 168 | ``` cs 169 | var p = Point(2,3); 170 | if (p matches Point(out x, out y)) { ... } 171 | ``` 172 | 173 | 174 | ## Discussion 175 | 176 | There were questions raised, heated discussions, and no agreed-upon answers. 177 | 178 | 179 | Q. If we go with primary constructors as they're currently envisaged (where the primary parameters *don't* define fields, and instead only exist at construction-time), then will we still be able to support this vision of pattern-matching? 180 | 181 | A. Not directly. But we could support this vision through a new modifier "record", e.g. `record class Point(int x, int y)` 182 | 183 | 184 | 185 | Q. What is the difference between putting all this "record" stuff (auto-generated properties, Equals, GetHashCode, Match operator) into the existing primary constructor syntax, vs putting them in via a new modifier "record" ? 186 | 187 | A1. It's a language-cleanliness problem. It would feel goofy for the primary constructor syntax to mean such different things depending on whether the "record" modifier is present. 188 | 189 | A2. Case is different. The convention in C# will be to use lower-case for primary constructor parameters, since users will write out the properties manually and use upper-case for that. But with records, the convention will probably be to use uper-case for the primary properties. 190 | 191 | 192 | 193 | Q. It feels wrong for primary-constructors to be so closely tied to immutable data and pattern-matching. Primary constructors have many other uses even when you don't want the rest, e.g. for coding visitor-patterns. Can we add all the features (primary constructors, Matches, Equals/GetHashCode, auto-generated properties) individually and orthogonally over time? And then use "concise declaration" (via whatever syntax) as the thread that ties everything together and delivers the smooth end-to-end use-case? 194 | 195 | A. Maybe our goal should be to make a concise story for the desired use-case, rather than to add orthogonal features? 196 | 197 | 198 | Q. Is it important that users can declare Match operators today, right from the first version of primary constructors? (granted, this would be pretty much useless on its own: the Match operator only becomes useful in conjunction with all the other features). 199 | 200 | 201 | 202 | Q. How would these "record types" work with serialization? People commonly use Plain Old CLR Objects (POCO) when they want DataContract serialization. But there's no clear way with this proposal to attribute the individual properties. 203 | 204 | 205 | 206 | Q. What's needed to ship in the first version of primary-constructors so as to allow this kind of evolution over time? Are there any conflicts with the current proposals (of primary-constructors and SelectCase) that would prevent such evolution? 207 | 208 | A. Neal and Mads will meet, discuss this question, and take it to C# LDM next week. 209 | 210 | -------------------------------------------------------------------------------- /meetings/2014/LDM-2014-07-01.md: -------------------------------------------------------------------------------- 1 | # #Warning Disable 2 | 3 | ## REQUEST 4 | 5 | Please add `#pragma` to VB so we can suppress warnings. This will be especially useful for Roslyn Diagnostics, where people will find many more warnings in their code. 6 | 7 | ## RESOLUTION 8 | 9 | Add two new preprocessor directives: 10 | 11 | ``` vb 12 | #Disable Warning 40008, BC42358, "BC42356" 13 | #Enable Warning 40008, BC42358, "BC42356" 14 | ``` 15 | 16 | ## ALTERNATIVE SYNTAXES CONSIDERED 17 | 18 | ``` vb 19 | #pragma disable 20 | #pragma enable 21 | 22 | #Disable ' sounds like you're disabling code, not warnings 23 | #Enable 24 | 25 | #Ignore 26 | #End Ignore ' block structure is worse than toggles 27 | 28 | #Disable Warning 29 | #Enable Warning 30 | ``` 31 | 32 | 33 | ## DISCUSSION 34 | 35 | The tradition in VB and its rich history of quick-fixes is that you resolve warnings by FIXING YOUR CODE, e.g. by doing whatever the quickfix says, adding an explicit cast, adding a return statement, ... 36 | 37 | Q. Do people really use #pragma much in C# today? Hard to say. With new Roslyn diagnostics, will *more* people start using #pragma in C# ? Will people write Roslyn diagnostics that have a much higher false-positive rate than existing rules, for people who wish to be more careful, safe in the knowledge that it's easy to suppress? 38 | 39 | Q. Is there a downside to adding #pragma to VB for suppressing warnings? - no, not really 40 | 41 | Q. Should we add a feature which suppresses the warning merely for the next line, rather than for the rest of the file? -- This isn't feasible in C# where lines don't really exist semantically. It is feasible for VB. Disadvantage: would confusing for LINQ, and not refactoring-safe. Advantage: if the lightbulb/quickfix appears for a warning, and when you chose the option to "suppress warning" then it only has to insert a single line to "suppress-warning-on-next-line", rther than having to insert `#ignore` before and `#restore` after. Conclusion: No we won't add this next-line-suppression feature. 42 | 43 | Q. Is it good to disable/enable on a "block" basis like `#Ignore / #End Ignore` ? Or on a toggle basis like `#Disable Warning / #Enable Warning` ? Well, with blocks you can't do overlapping regions. And you can't easily disable warnings for an entire method but then re-enable them for a small critical region inside (even though that's a weird scenario). We believe overall that toggles are nicer. They have a lot of engineering, thought and experience behind them. 44 | 45 | Q. For the ``, should quotation marks be obligatory? - No. You can use any identifier or integer. It's only if the warning-id has spaces or other weird characters that you'd need quotation marks. 46 | 47 | Q. Should we allow pure integers for the ``, with the expectation that they disable intrinsic VB compiler warnings? All user-defined warnings (that come through Roslyn diagnostics) would have error codes that aren't pure integers. -- Yes, let's allow integers, just like C#, and just like the VB command-line. It will be a common case. 48 | 49 | Q. Will the Roslyn diagnostics APIs allow people to define error codes that are just pure numbers, even though they'll be impossible to disable them? -- No real need. Diagnostic-authors will learn soon enough not to do this. 50 | 51 | Q. Should we allow you to disable/enable command-separated lists of warnings in a single `#Disable Warning / #Enable Warning` directive? -- Yes. 52 | 53 | Q. Preprocessor directives look ugly because they're always left-aligned. Can we make it so preprocessor directives can be indented? There's a uservoice request for it. -- Not discussed; left for another day. 54 | 55 | 56 | # Back-compat break with interface implementations 57 | 58 | We also discussed another topic to do with ambiguity between unrelated interfaces. Discussion is in this thread: 59 | https://roslyn.codeplex.com/discussions/570975 60 | 61 | # Update: VB LDM 2014.07.01 62 | 63 | We re-visited #Disable Warning. The summary for VB is: 64 | 65 | * Use the syntax `#Disable Warning id1, id2, ...` 66 | * The warning IDs must parse as per the same rules of VB identifiers, and are case-insensitive. That rules out plain numbers `#Disable Warning 4008` (instead you must disable BC4008) and it rules out strings `#Disable Warning "Don't Use Capitals!"`. That means you can't disable warnings that have fancy error codes with punctuation and so on. 67 | * This will guide users to the thought that they can right-click, find all references, and opens up the mental door to other refactorings/tooling 68 | * We will restrict what identifiers can be produced at the production side too, when authoring analyzers 69 | * We used to give BC2026 “that warning can’t be configured” when you try to nowarn or warnaserror on non-existent warnings (and also on certain named warnings e.g. 2026). But that wouldn’t work for diagnostic warning codes. So let’s no longer emit BC2026 ever. Instead, if you try to disable or enable a non-existing warning, simply do nothing. 70 | * Stretch goal: the IDE could grey out all identifiers that have been disabled but are never actually generated by the code 71 | 72 | C# will be mostly similar, but 73 | * C# will support disabling warnings/errors by number as well as by identifier, and is case sensitive. It has to support disabling numbers for back-compat. If you disable warning number 4008, that's equivalent to disabling identifier CS4008. 74 | * As with VB, we stop validating whether the warning code is a legal compiler warning ID (both on the command-line and inside #pragma) - CS1691 will no longer be reported for C#. 75 | 76 | Things that fall out for free: 77 | * No changes required to disallow Hexadecimal, Octal, Long etc. literals 78 | * No need to worry about making BC2026 unerrorable 79 | 80 | For the future: 81 | * Update lightbulb suppression to always generate #pragma / #disable with identifiers. (Do we need to check that the id will be a legal identifier before spitting the code?) 82 | * Fix /nowarn and /warnaserror command-line switches to support custom diagnostics 83 | * Implement grey out for “unused” ids in #pragma, #Disable (plus corresponding code fix) 84 | * Have some way for users to get from a reported warning id / from a warning id used in #pragma or #Disable to a description of the diagnostic 85 | * Support for qualified identifiers that use dots (only if customers ask for it) 86 | 87 | 88 | -------------------------------------------------------------------------------- /meetings/2014/LDM-2014-10-01.md: -------------------------------------------------------------------------------- 1 | There were two agenda items... 2 | 1. Assignment to readonly autoprops in constructors (we fleshed out details) 3 | 2. A new compiler warning to prevent outsiders from implementing your interface? (no, leave this to analyzers) 4 | 5 | # Assignment to readonly autoprops in constructors 6 | 7 | ```cs 8 | public struct S { 9 | public int x {get;} 10 | public int y {get; set;} 11 | public Z z {get;} 12 | 13 | public S() { 14 | x = 15; 15 | y = 23; 16 | z.z1 = 1; 17 | } 18 | } 19 | 20 | public struct Z { int z1; } 21 | ``` 22 | 23 | _What are the rules under which assignments to autoprops are allowed in constructors?_ 24 | 25 | __Absolute__ We can't be more permissive in what we allow with readonly autoprops than we are with readonly fields, because this would break PEVerify. (Incidentally, PEVerify doesn't check definite assignment in the constructor of a struct; that's solely a C# language thing). 26 | 27 | __Overall principle__ When reading/writing to an autoprop, do we go via the accessor (if there is one) or do we bypass it (if there is one) and access the underlying field directly? 28 | _Option1:_ language semantics say the accessor is used, and codegen uses it. 29 | _Option2:_ in an appropriate constructor, when there is a "final" autoprop (either non-virtual, or virtual in a sealed class), access to an autoprop _means_ an access to the underlying field. This meaning is used for definite assignment, and for codegen. Note that it is semantically visible whether we read from an underlying field vs through an accessor, e.g. in `int c { [CodeSecurity] get;}` 30 | _Resolution: Option1_. Under Option2, if you set a breakpoint on the getter of an autoprop, gets of it would not hit the breakpoint if they were called in the constructor which is weird. Also it would be weird that making the class sealed or the autoprop non-virtual would have this subtle change. And things like Postsharper wouldn't be able to inject. All round Option2 is weird and Option1 is clean and expected. 31 | 32 | __Definite Assignment__. Within an appropriate constructor, what exactly are the rules for definite assignment? Currently if you try to read a property before _all_ fields have been assigned then it says CS0188 'this' cannot be used before all fields are assignment, but reading a field is allowed so long as merely that field has been assigned. More precisely, within an appropriate constructor, for purposes of definite assignment analysis, when does access of the autoprop behave as if it's an access of the backing field? 33 | _Option1_: never 34 | _Option2_: Only in case of writes to readonly autoprops 35 | _Option3_: In the case of writes to all autoprops 36 | _Option4_: In the case of reads and writes to all autoprops 37 | _Resolution: Option4_. This is the most helpful to developers. You might wonder what happens if it's a virtual autoprop and someone overrides getter or setter in derived types in such a way that would violate the definite assignment assumptions. But for structs there won't be derived types, and for classes the semantics say that all fields are assigned to default(.) so there's no difference. 38 | 39 | __Piecewise initialization of structs__. In the code above, do we allow `z.z1 = 15` to assign to the _field_ of a readonly struct autoprop? 40 | _Option1:_ Yes by threating access to "z" for purposes of definite assignment as an access of the underlying field. 41 | _Option2: _ No because in `z.z1` the read of `z` happens via the accessor as per the principle above, and thus returns an rvalue, and hence assignment to `z.z1` can't work. Instead you will have to write `z = new Z(...)`. 42 | _Resolution: Option2_. If we went with Option1, then readonly autoprops would end up being more expressive than settable autoprops which would be odd! Note that in VB you can still write `_z.z1 = 15` if you do want piecewise assignment. 43 | 44 | __Virtual__. What should happen if the readonly autoprop is virtual, and its getter is overridden in a derived class? 45 | _Resolution:_ All reads of the autoprop go via its accessor, as is already the case. 46 | 47 | __Semantic model__. In the line `x = 15` what should the Roslyn semantic model APIs say for the symbol `x` ? 48 | _Resolution:_ they refer to the property x. Not the backing field. (Under the hood of the compiler, during lowering, if in an appropriate constructor, for write purposes, it is implicitly transformed into a reference to the backing field). More specifically, for access to an autoprop in the constructor, 49 | 1. It should _bind_ to the property, but the property should be treated as a readable+writable (for purposes of what's allowed) in the case of a readonly autoprop. 50 | 2. The definite assignment behavior should be as if directly accessing the backing field. 51 | 3. It should code gen to the property accessor (if one exists) or a field access (if not). 52 | 53 | __Out/ref arguments in C#__. Can you pass a readonly autoprop as an out/ref argument in C#? 54 | _Resolution: No_. For readonly autoprops passed as _ref_ arguments, that wouldn't obey the principle that access to the prop goes via its accessor. For passing readonly autoprops as _out_ arguments with the hope that it writes to the underlying field, that wouldn't obey the principle that we bind to the property rather than the backing field. For writeonly autoprops, they don't exist because they're not useful. 55 | 56 | __Static readonly autoprops__ Should everything we've written also work for static readonly autoprops? 57 | _Resolution: Yes._ Note there's currently a bug in the native compiler (fixed in Dev14) where the static constructor of a type G is able to initialize static readonly fields in specializations of G e.g. `G.x=15;`. The CLR does indeed maintain separate storage locations for each static readonly fields, so `G.g` and `G.g` are different variables. (The native compiler's bug where the static constructor of G could assign to all of them resulted in unverifiable code). 58 | 59 | __VB rules in initializers as well as constructors__. VB initializers are allowed to refer to other members of a class, and VB initializers are all executed during construction time. Should everything we've said about behavior in C# constructors also apply to behavior in VB initializers? 60 | _Resolution: Yes_. 61 | 62 | __VB copyback for ByRef parameters__. In VB, when you pass an argument to a ByRef parameter, then either it passes it as an lvalue (if the argument was a local variable or field or similar) or it uses "copy-in to a temporary then invoke the method then copy-out from the temporary" (if the argument was a property), or it uses "copy-in to a temporary then invoke the method then ignore the output" (if the argument was an rvalue or a constant). What should happen when you pass a readonly autoprop to a ByRef parameter? 63 | _Option1:_ Emit a compile-time error because copyback is mysterious and bites you in mysterious ways, and this new way is even more mysterious than what was there before. 64 | _Option2:_ Within the constructor/initializers, copy-in by reading via the accessor, and copy-back by writing to the underlying field. Elsewhere, copy-in with no copy-out. Also, just as happens with readonly fields, emit an error if assignment to a readonly autoprop happens in a lambda in a constructor (see code example below) 65 | _Resolution: Option2_. Exactly has happens today for readonly fields. Note incidentally that passing a readonly autoprop to a ByRef parameter will have one behavior in the constructor and initializers (it will do the copy-back), and will silently have different behavior elsewhere (it won't do any copy-back). This too is already the case with readonly fields. On a separate note, developers would like to have feedback in some cases (not constants or COM) where copyback in a ByRef argument isn't done. But that's not a question for the language design meeting. 66 | 67 | __VB copyin for writeonly autoprops__. VB tentatively has writeonly autoprops for symmetry, even though they're not useful. What should happen when you pass a writeonly autoprop as a ByRef argument? 68 | _Resolution: Yuck._ This is a stupid corner case. Notionally the correct thing is to read from the backing field, and write via the setter. But if it's easier to just remove support for writeonly autoprops, then do that. 69 | 70 | ```vb 71 | Class C 72 | ReadOnly x As Integer = 15 73 | 74 | Public Sub New() 75 | f(x) 76 | Dim lamda = Sub() 77 | f(x) ' error BC36602: 'ReadOnly' variable 78 | ' cannot be the target of an assignment in a lambda expression 79 | ' inside a constructor. 80 | End Sub 81 | End Sub 82 | Shared Sub f(ByRef x As Integer) 83 | x = 23 84 | End Sub 85 | End Class 86 | ``` 87 | 88 | We discussed a potential new error message in the compiler. 89 | 90 | __Scenario:__ Roslyn ships with ISymbol interface. In a future release it wants to add additional members to the interface. But this will break anyone who implemented ISymbol in its current form. Therefore it would be good to have a way to prevent anyone _else_ from implementing ISymbol. That would allow us to add members without breaking people. 91 | 92 | Is this scenario widespread? Presumably, but we don't have data and haven't heard asks for it. There are a number of workarounds today. Some workarounds provide solid code guarantees. Other workarounds provide "suggestions" or "encouragements" that might be enough for us to feel comfortable breaking people who took dependencies where we told them not to. 93 | 94 | __Counter-scenario:__ Nevertheless, I want to _MOCK_ types. I want to construct a mock ISymbol myself maybe using MOQ, and pass it to my functions which take in an ISymbol, for testing purposes. I still want to be able to do this. (Note: MOQ will automatically update whenever we add new members to ISymbol, so users of it won't be broken). 95 | 96 | 97 | __Workarounds__ 98 | 99 | 1. Ignore the problem and just break people. 100 | 2. Like COM, solve it by adding new incremental interfaces ISymbol2 with the additional members. As Adam Speight notes below, you can make ISymbol2 inherit from ISymbol. 101 | 3. Instead of interfaces, use abstract classes with internal constructors. Or abstract classes but never add abstract methods to it; only virtual methods. 102 | 4. Write documentation for the interface, on MSDN or in XML Doc-Comments, that say "Internal class only; do not implement it". We see this for instance on ICorThreadpool. 103 | 5. Declare a method on the interface which has an internal type in its signature. The CLR allows this but the language doesn't so it would have to be authored in IL. Every type which implements the interface would have to provide an implementation of that method. 104 | 6. Write run-time checks at the public entry points of key Roslyn methods that take in an ISymbol, and throw if the object given was implemented in the wrong assembly. 105 | 7. Write a Roslyn analyzer which is deployed by the same Nuget package that contains the definition of ISymbol, and have this analyzer warn if you're trying to implement the interface. This analyzer could be part of Roslyn, or it could be an independent third-party analyzer used by many libraries. 106 | 107 | 108 | __Proposal:__ Have the compiler recognize a new attribute. Given the following code 109 | ```cs 110 | [System.Runtime.CompilerServices.InternalImplementationOnly] interface I<...> {...} 111 | ``` 112 | it should be a compile-time warning for a type to implement that interface, directly or indirectly, unless the class is in the same assembly as "I" or is in one of its InternalsVisibleTo friends. It will also be a compile-time error for an interface to inherit from the interface in the same way. Also, we might ask for the .NET Framework team to add this attribute in the same place as System.Runtime.CompilerServices.ExtensionAttribute, and CallerMemberNameAttribute. But doing it isn't necessary since the compiler will recognize any attribute with that exact fully-qualified name and the appropriate (empty) constructor. 113 | 114 | Note that this rule would not be cast-iron, since it won't have CLR enforcement. It would still be possible to bypass it by writing IL by hand, or by compiling with an older compiler. But we're not looking for cast-iron. We're just looking for discouragement strong enough to allow us to add members to ISymbol in the future. (In the case of ISymbol, it's very likely that people will be using Roslyn to compile code relating to ISymbol, but that doesn't apply to other libraries). 115 | 116 | 117 | __Resolution:__ Workaround #7 is a better option than adding this proposal to the language. 118 | -------------------------------------------------------------------------------- /meetings/2014/LDM-2014-10-08.md: -------------------------------------------------------------------------------- 1 | # Back-compat break with interface implementations 2 | 3 | ## High-level summary 4 | 5 | * _On the declaration side,_ C# users always used to be able to declare overloads of ambiguous interface methods. We are adding this ability also to VB for VS2015. 6 | * _On the consumption side,_ C# language is more "hide-by-name" while VB supports both "hide-by-name" and "hide-by-sig". 7 | * In such cases VB used to try to emulate the C# behavior when meta-importing such declarations. Now it will follow the more VB behavior. 8 | * _This will cause some small breaking changes_. The breaking cases are limited to where... 9 | * (1) Library code was authored in C# 10 | * (2) In that library an interface ID inherits from two others IA,IB and declares a more general overload of a method in each of them 11 | * (3) VB consumers of that library used to pick the more general overload (copying C#'s hide-by-name behavior). But now they will pick the more specific overload (using VB's hide-by-sig behavior) 12 | * (4) If there were ambiguous specific overloads then it will be a break for VB consumers of the C# library. 13 | 14 | 15 | ## Background 16 | 17 | ``` vb 18 | Interface A 19 | Sub M(x As Integer) 20 | End Interface 21 | 22 | Interface B 23 | Sub M(x As String) 24 | End Interface 25 | 26 | Interface C : Inherits A,B 27 | Overloads Sub M(x As Char) 28 | End Interface 29 | 30 | Interface D : Inherits A, B 31 | End Interface 32 | ``` 33 | 34 | DECLARATION: Declaration C" had been illegal in VB up to VS2013; you could only declare M in C with 'Shadows, or meta-import it from C#. But VB Roslyn made a change... it now lets you *declare* such things. 35 | 36 | CONSUMPTION: We never came up with a policy around CONSUMPTION of such things. 37 | 38 | * VS2013: In the type "C" if you try to access "M", the compiler doesn't see "M" from A and B. It only sees it from C. Note: you can meta-import C, but can't declare it. 39 | * VS2013: In the type "D" if you try to access "M", the compiler gives a name-lookup ambiguity error prior to even attempting overload resolution. 40 | * Roslyn as of May 2014: In both "C" and "D" if you try to access "M", the compiler gives name-lookup ambiguity error prior to even considering overload resolution. 41 | 42 | ## Request 43 | 44 | We'd like to be able to invoke "M" in both "C" and "D". But we'd also like to preserve backwards compatibility. It's a conundrum. 45 | 46 | 47 | Note that there's a similar issue with Modules: 48 | ``` vb 49 | Module Module1 50 | Function Sin(d As Double) As Double 51 | 52 | Modle Module2 53 | Function Sin(s As Single) As Single 54 | 55 | ' this callsite is in a place that imports both modules' containing namespaces 56 | Dim x = Sin(1.0) ' VB currently makes this an ambiguity. 57 | ``` 58 | VB makes this invocation of Sin an ambiguity. But when you do the equivalent in C# using "static using", it gathers together all candidates from all usings, and then performs overload resolution on them. This case seems very minor. Not worth worrying about. 59 | 60 | ## VB LDM 2014.04.16 61 | 62 | PROPOSAL1: revert change that enabled declaration in C. (but doesn't help consumption of meta-imported C, nor consumption of D). 63 | 64 | PROPOSAL2: silently treat it as shadowing at the callsite, consistent with native compiler. (but doesn't help consumption of D). 65 | 66 | _PROPOSAL3: Allow at lookup, i.e. merge them all, and leave it to overload resolution. (This is the proposal that we picked)._ This is a small breaking change. It will break code which used to meta-import "C", and invoked "M" in it, and always got the version of "M" in "C". Now with this change, it might get the version of "M" from "A" or "B". We think this is a minor breaking change, because (1) it only applied to meta-import situations, (2) it will now behave as the author intended. Note that this requires a change to VB spec 4.3.2. 67 | 68 | PROPOSAL4: combination of 1 and 2, i.e. completely duplicate behavior of native compiler. 69 | 70 | ## VB LDM 2014.10.08 71 | 72 | We revisited the previous conclusion in the light of implementation. The related bug numbers are: 73 | https://roslyn.codeplex.com/workitem/34 74 | Internal vstfdevdiv bug 527642 75 | 76 | The issue is that the C# language has hide-by-name lookup rules, and because of this it doesn't matter whether it meta-exports its signatures as "hide-by-name" or "hide-by-sig"; that difference is ignored. It happens to export them as "hide-by-sig". 77 | 78 | 79 | Here's a representative example of the kind of breaks we'll now get under PROPOSAL3. There is a library that was authored in C#: 80 | ```cs 81 | interface IA {void m(int x);} 82 | interface IB {void m(int x);} 83 | interface ID : IA,IB {void m(object x);} 84 | ``` 85 | C# users of the library are able to use it fine: 86 | ```cs 87 | ID d = null; 88 | d.m(1); // picks the "object" overload 89 | ``` 90 | However VB users of the library will now experience a break 91 | ```vb 92 | Dim x As ID = Nothing 93 | x.m(1) ' VS2013 used to pick 'Object' but under Proposal3 will now give an ambiguity error 94 | x.m(CObj(1)) ' this is the workaround to use in this case 95 | ``` 96 | 97 | The breaking cases are limited to where C# had ambiguous methods in unrelated interfaces, and overrode them with a more general overload in the derived interface ID. We imagine this breaking case will be uncommon. 98 | 99 | 100 | 101 | There's a more common related scenario which WILL CONTINUE to work just fine. Let's walk through it: 102 | ```cs 103 | interface IJson {string GetName();} 104 | interface IComponent {string GetName();} 105 | interface IPatient : IJson,IComponent {} 106 | ``` 107 | I am a C# author. I am taking in two libraries that provide IJson and IComponent. They are unrelated by they happen to have a method which shares a signature and has more or less the same behavior. I write it as above. However, within my C# use of my library, I discover a problem straight away: `IPatient y = ...; y.GetName();` This code will give a compile-time ambiguity error because it doesn't know which unrelated overload of GetName to use. So I fix up my C# library as follows, to silence up the compiler: 108 | ```cs 109 | interface IPatient : IJson,IComponent {new string GetName();} 110 | ``` 111 | With this change, the same C# code `IPatient y = ...; y.GetName();` will work just fine. The reason it works in C# is because C# language uses hide-by-name lookup rules, and finds IPatient.GetName, and is happy with that. 112 | ```vb 113 | Dim y As IPatient = Nothing 114 | y.GetName() ' correctly picks IPatient.GetName 115 | ``` 116 | Fortunately the VB consumers of the library will also work great. In VS2013 it worked because VB faked up hide-by-name semantics on meta-import and so got the derived class. Under Proposal3 it will work because VB honestly uses hide-by-sig semantics and in this case (unlike ID.m(object) above) the hide-by-sig semantics pick the correct method. 117 | 118 | 119 | How did VS2013 VB fake up "hide-by-name" semantics? Well, upon meta-import, it did a "shadowing trick": if it encountered an interface like C, it knew that such an interface could not have been declared by VB, and therefore it must have been declared in C#, and C# language had hide-by-name (shadowing) semantics, and so VB ignored the "hide-by-sig" attribute on the metadata and imported it as hide-by-name. 120 | 121 | 122 | We went back on our resolution. We decided to forbid declaration of interfaces like "C". By forbidding it, we open the door to pulling the same "shadowing" trick as VS2013 did on meta-import. Actually the Roslyn compilers have a cleaner design and can't pull the trick on meta-import; however they can pull it on name lookup. 123 | 124 | In other words, we resolved to go for PROPOSAL4. 125 | 126 | ## VB LDM 2014.10.08 127 | 128 | Gosh this is difficult. In trying to replicate the behavior of VS2013, Aleksey discovered some pretty weird bugs in the way VS2013 applied its shadowing heuristics. 129 | 130 | ```vb 131 | ' BUG NUMBER 1 IN VS2013 132 | 133 | Interface IA(Of T) 134 | Sub M1(x As T) 135 | End Interface 136 | 137 | Interface IB 138 | Inherits IA(Of Integer), IA(Of Short) 139 | Overloads Sub M1(x As String) ' VS2013 doesn't report an error 140 | End Interface 141 | 142 | Interface IC1 143 | Sub M1(x As Integer) 144 | End Interface 145 | 146 | Interface IC2 147 | Sub M1(x As Short) 148 | End Interface 149 | 150 | Interface ID 151 | Inherits IC1, IC2 152 | Overloads Sub M1(x As String) ' VS2013 reports error BC31410 "Overloading methods declared in multiple base interfaces is not valid" 153 | End Interface 154 | 155 | Module Module2 156 | Sub Test(x As IB) 157 | x.M1(1) ' VS2013 reports error BC30685: 'M1' is ambiguous across the inherited interfaces 'IA(Of Integer)' and 'IA(Of Short)' 158 | End Sub 159 | 160 | Sub Test(x As ID) 161 | x.M1(1) 'ID 162 | End Sub 163 | End Module 164 | ``` 165 | What's strange in this bug number 1 is that you expect the declaration error BC31410 to be reported in both cases IB and ID. However VS2013 only reports a declaration error for ID. Instead it reports a consumption error for IB. 166 | 167 | ```vb 168 | ' BUG NUMBER 2 IN VS2013 169 | 170 | Interface IA 171 | Sub M1() 172 | End Interface 173 | 174 | Interface IB 175 | Inherits IA 176 | Overloads Sub M1(x As Integer) 177 | End Interface 178 | 179 | Interface IC1 180 | Inherits IA, IB 181 | Overloads Sub M1(x As String) ' VS2013 reports error BC31410 "Overloading methods declared in multiple base interfaces is not valid." 182 | End Interface 183 | 184 | Interface IC2 185 | Inherits IB, IA 186 | Overloads Sub M1(x As String) ' VS2013 reports error BC31410 "Overloading methods declared in multiple base interfaces is not valid." 187 | End Interface 188 | 189 | Interface IC3 190 | Inherits IB 191 | Overloads Sub M1(x As String) ' VS2013 reports no error 192 | End Interface 193 | ``` 194 | What's strange about this is that interfaces IC1, IC2 and IC3 are semantically equivalent: whether or not you explicitly declare that you inherit from IA is irrelevant, since it's implied. So the compiler shouldn't be reporting a declaration error in IC1/IC2, just as it doesn't report a declaration error in IC3. 195 | 196 | This means that we have to refine our idea of Proposal 4: 197 | 198 | PROPOSAL4a: disallow declaration C by reimplementing all the weird quirks of VS2013, and use implicit shadowing upon name lookup. We rejected this as too difficult: Roslyn has very different code paths, so there's a high risk that we'd get different behavior from VS2013. 199 | 200 | PROPOSAL4b: disallow declaration C in a clean way without any of the weird quirks of VS2013. 201 | 202 | The question is: out of Proposal3 and Proposal4b, which will be the most painful break? 203 | 204 | Proposal4b will hurt people who declare things that used to be okay under the old quirky rules but are no longer okay. We haven't discovered many cases yet. 205 | 206 | Proposal3, as we said before, will hurt people who invoked x.m(1) in the case identified above. Their workaround is to change the callsite with an explicit cast. There is precedent for this: the overload resolution rules between VB and C# are different, and VB people have to put explicit casts in other callsites. 207 | 208 | COM is an interesting case where you generally have IFoo1 and IFoo2 where IFoo2 duplicates (doesn't inherit) the methods of IFoo but also adds a few others. However we don't see this as a problem. It's very nontypical to declare a third interface IBar which inherits both IFoo1 and IFoo2 in COM scenarios. 209 | 210 | In the light of this new evidence, we prefer Proposal3. It will be a better cleaner future for the VB language to declare things like this. And it puts the pain on callsites to ambiguous interfaces, rather than producers of them; it's generally easier to fix callsites. As for the breaking changes, some of them will be silently picking more appropriate overloads, which is generally the right thing to do and more intuitive. Only in rare and contrived cases (where C# author overrides two ambiguous specific methods with a less specific methods) will there be a compile-time failure. 211 | 212 | Note that the VS2015 CTP4 (already shipped by the time we had this LDM) lets you declare things like "C" but there's not even any overload resolution at the callsite. That will give us lots of opportunity to hear from customers whether they're suffering from the fact that we no longer do implicit shadowing. If we hear pain, then we can re-visit. 213 | 214 | -------------------------------------------------------------------------------- /meetings/2014/README.md: -------------------------------------------------------------------------------- 1 | # Visual Basic .NET Language Design Notes for 2014 2 | 3 | Overview of meetings and agendas for 2014 4 | 5 | 6 | ## Feb 17, 2014 7 | 8 | [Visul Basic .NET Design Meeting Notes for Feb 17, 2014](LDM-2014-02-17.md) 9 | 10 | a complete roll-up of all language features that are on the table 11 | 12 | 13 | ## Feb 10, 2014 14 | 15 | [Visul Basic .NET Design Meeting Notes for Feb 10, 2014](LDM-2014-02-10.md) 16 | 17 | 18 | Strict Module 19 | 20 | 21 | ## Mar 12, 2014 22 | 23 | [Visul Basic .NET Design Meeting Notes for Mar 12, 2014](LDM-2014-03-12.md) 24 | 25 | ProtectedAndFriend access modifier, and faster CInt(.) 26 | 27 | ## Apr 1, 2014 28 | 29 | [Visul Basic .NET Design Meeting Notes for Apr 1, 2014](LDM-2014-04-01.md) 30 | 31 | String interpolation 32 | 33 | 34 | ## Apr 2, 2014 35 | 36 | [Visul Basic .NET Design Meeting Notes for Apr 2, 2014](LDM-2014-04-02.md) 37 | 38 | Null-propagating operator ?. 39 | 40 | ## Apr 16, 2014 41 | 42 | [Visul Basic .NET Design Meeting Notes for Apr 16, 2014](LDM-2014-04-16.md) 43 | 44 | #Disable Warning, and ambiguity from unrelated interfaces 45 | 46 | ## Apr 23, 2014 47 | 48 | [Visul Basic .NET Design Meeting Notes for Apr 23, 2014](LDM-2014-04-23.md) 49 | 50 | primary constructors, and pattern-matching. 51 | 52 | ## Jul 1, 2014 53 | 54 | [Visul Basic .NET Design Meeting Notes for Jul 7, 2014](LDM-2014-07-01.md) 55 | 56 | #Disable Warning revisited 57 | 58 | ## Oct ,1 2014 59 | 60 | [Visul Basic .NET Design Meeting Notes for Oct 1, 2014](LDM-2014-10-01.md) 61 | 62 | rules for assignment to readonly autoprops in constructors, and preventing outsiders from implementing your interfaces 63 | 64 | ## Oct 8, 2014 65 | 66 | [Visul Basic .NET Design Meeting Notes for Oct 8, 2014](LDM-2014-10-08.md) 67 | 68 | revisit "ambiguity from unrelated interfaces" 69 | 70 | ## Oct 15, 2014 71 | 72 | [Visul Basic .NET Design Meeting Notes for Oct 15, 2014](LDM-2014-10-15.md) 73 | 74 | revised nameof operator 75 | 76 | 77 | ## Oct 23, 2014 78 | 79 | [Visul Basic .NET Design Meeting Notes for Oct 23, 2014](LDM-2014-10-23.md) 80 | 81 | revised nameof operator again. (Also some breaking changes for ambiguous unrelated interface members) -------------------------------------------------------------------------------- /meetings/2015/LDM-2015-01-14-VB.md: -------------------------------------------------------------------------------- 1 | VB Design Meeting 2015-01-14 2 | ============================ 3 | 4 | # Overload Resolution for String Interpolation 5 | 6 | Discussion thread for these notes can be found at https://github.com/dotnet/roslyn/issues/46. 7 | 8 | # Summary 9 | 10 | * Exactly like C#, we will consider an interpolated string to be like a string in most cases such as overload resolution and searches for user-defined/intrinsic conversion. This implies that what the IDE intellisense shows after $"hello".| should be the same as that for regular strings. 11 | 12 | * We wrote out some gnarly type-inference test cases for overload resolution and array literals with interpolated strings, and explained the expected output. 13 | 14 | * We would like both C# and VB to give more actionable error messages if they end up binding to a factory Create method whose return type isn't right 15 | 16 | * We reaffirmed intended behavior for full-width characters in interpolated strings 17 | 18 | # Overload resolution for string interpolation 19 | 20 | We want interpolated strings to be easily used as both String and FormattableString: 21 | ```vb 22 | Dim x As String = $"hello {p}" ' works fine 23 | Dim x As FormattableString = $"hello {p}" ' works fine 24 | Dim x = $"hello {p}" ' works fine, and infers x As String 25 | ``` 26 | 27 | The question is about overload resolution... Which candidate should it prefer? Or should it be an ambiguity error? 28 | ```vb 29 | Sub f(x As FormattableString) : End Sub 30 | Sub f(x As String) : End Sub 31 | 32 | f($"hello {p}") ' ... which does it pick? 33 | ``` 34 | 35 | One important principle is that if there's an existing API `Sub f(x As String)` then consumers MUST be able to call it with `f($"hello {p}")`. 36 | 37 | 38 | Another question is: if there's a language intrinsic conversion from string, does that conversion also apply to interpolated strings? e.g. 39 | ```vb 40 | Dim x As Char() = "hello people" ' works fine 41 | Dim x As Char() = $"hello {x}" ' should this also work? 42 | ``` 43 | And separately, if there's a user-defined intrinsic conversion from string, does that conversion also apply to interpolated strings? 44 | 45 | (In C# the intention is that both should work. Have to verify that we've covered that in unit tests.) 46 | 47 | 48 | 49 | ## API DESIGN Proposal 1a 50 | "Some library APIs really want consumers to use FormattableString because it is safer or faster. The API that takes string and the API that takes FormattableString actually do different things and hence shouldn't be overloaded on the same name. Library authors will want to lead people to use interpolated strings, hence it should have a shorter name." 51 | ```vb 52 | Sub ExecuteQueryUnsafe(s As String) ... 53 | Sub ExecuteQuery(s As FormattableString) ... 54 | 55 | Sql.ExecuteQueryUnsafe(GetRegValueEx(path)) 56 | Sql.ExecuteQueryUnsafe("from p in people select p.Name") 57 | Sql.ExecuteQuery($"from p in {x} select p.Name") 58 | ``` 59 | 60 | Q. If they do different things, then wouldn't you want an ambiguity error here? 61 | 62 | 63 | ## API DESIGN Proposal 1b 64 | "In other library APIs, strings and FormattableStrings are equally fine; overloads make sense; we should prefer string overload because it will be more efficient" 65 | ```vb 66 | Sub WriteLine(s As String) ... 67 | 68 | Console.WriteLine("hello everyone") 69 | Console.WriteLine($"hello {fred}") 70 | ``` 71 | 72 | Q. Isn't it an *antipattern* for an API to have both String and FormattableString if they just do the same thing? 73 | 74 | A. Well, maybe, but it could be valid and useful to overload on both String and IFormattable. (Or an overload of both String and Object and then do a TryCast to IFormattable). 75 | 76 | 77 | ## Proposal 2 78 | "I don't like Safe/Unsafe. How about these names? ..." 79 | ```vb 80 | Sub ExecuteQuery(s As String) ... 81 | Sub ExecuteQuery(s As FormattableString) ... 82 | 83 | Sql.ExecuteQuery(GetRegValueEx(path)) 84 | Sql.ExecuteQuery("from p in people select p.Name") 85 | Sql.ExecuteQueryWithFormat($"from p in {x} select p.Name") 86 | ``` 87 | 88 | 89 | ## API DESIGN Proposal 3 90 | "Someone will start with ExecuteQuery, and when they change the argument to $ then they won't see or understand the differently-named method. So let's pick the FormattableString overload which is most likely to be safe." 91 | ```vb 92 | Sub ExecuteQuery(s As String) ... 93 | Sub ExecuteQuery(s As FormattableString) ... 94 | 95 | Sql.ExecuteQuery("from p in people select p.Name") ' picks String overload 96 | Sql.ExecuteQuery(GetRegValueEx(path)) ' picks String overload 97 | Sql.ExecuteQuery($"from p in {x} select p.Name") ' picks FormattableString overload 98 | ``` 99 | 100 | Q. What about the following consequence? Imagine an API has existed whose behavior is to format its string in a particular culture 101 | ```vb 102 | Sub f(x As IFormattable) 103 | f($"hello {p}") 104 | ``` 105 | And later on down the line someone adds a new overload that takes string 106 | ```vb 107 | Sub f(x As String) 108 | ``` 109 | Then the user's call will change behavior upon recompilation. 110 | 111 | 112 | ## RESOLUTION 113 | We generally believe that libraries will mostly be written with different API names for methods which do different things. Therefore overload resolution differences between FormattableString and String don't matter, so string might as well win. Therefore we should stick with the simple principle that an interpolated string *is* a string. End of story. 114 | 115 | Implication: in intellisense `$"hello".|` will show extension methods off String, but will *NOT* show extension methods off FormattableString. 116 | 117 | Implication: both intrinsic and user-defined conversions that apply to string will also apply to interpolated string 118 | 119 | Implication: overload resolution will prefer String over FormattableString candidates when given an interpolated string argument. 120 | 121 | Implication: type inference works as follows. 122 | ```vb 123 | Sub f(Of T)(x As T) 124 | f($"hello {p}") 125 | ' then it picks string. (it has *contributed* string as a candidate) 126 | 127 | Sub f(Of T)(x As T, y As T) 128 | f($"hello {p}", CType(Nothing, FormattableString)) 129 | ' Then it gets two candidates, "String" and "FormattableString" 130 | ' In most of the language (other than array literals), it checks whether 131 | ' the *type* of each argument can convert to the candidate type. 132 | ' In this case it will give an error. 133 | ``` 134 | 135 | Implication: if you have an array literal that contains an interpolated string expression 136 | ```vb 137 | Dim x = {$"hello", CType(Nothing, IFormattable)} 138 | ``` 139 | then this will pick "Object Assumed" in Option Strict Off, and give an error in Option Strict On. The reason is that there is no dominant type between the candidate types "String" and "IFormattable". (There's no widening/identity conversion from one to the other, and there is a narrowing conversion from each to the other). 140 | 141 | 142 | ## About the factory method that interpolation strings use 143 | 144 | The language conversion rules bake in knowledge of `System.IFormattable` and `System.FormattableString` for their knowledge of widening conversions. 145 | 146 | The compiler emits a call to a factory method when there is an interpolated string in source code. The factory method looks like this. There might be a whole family of overloaded Create methods. 147 | ```vb 148 | System.Runtime.CompilerServices.FormattableStringFactory 149 | Function Create(...) As ... 150 | ``` 151 | The compiler separates the interpolated-string into a format string and a comma-separated list of expressions for the holes which it classifies as values before generating a call to `Create(fmtstring, expr1, expr2, ...)`. It will rely on normal VB overload resolution to pick the best Create method. This leaves the implementors of the factory free to do lots of nice optimizations. 152 | 153 | The question is, what return type do we expect from the Create method? 154 | 155 | Option1: We could bake in the requirement that the factory method gives back a System.FormattableString, and this type must implement System.IFormattable, and do this as a pre-filter prior to doing overload resolution of the Create() overload family. 156 | 157 | Option2: Or we could merely invoke the method, and do a cast of the return type to IFormattable/FormattableString depends on what the user asked for. But then... 158 | * Do we give a warning if it has the [Obsolete] attribute? 159 | * Do we give a warning if it is narrowing? 160 | * What if it picks a Sub() ? 161 | 162 | Option3: Just do plain ordinary overload resolution, and if there were ANY errors or warnings, them emit them. In addition, if there were any errors (not just warnings that happened to be WarnAsError'd), then additionally report an error message at the same location "The factory is malformed". Precedent: we do this for queries. [Note: this message might appear or disappear if you change option strict on/off in your file]. 163 | 164 | Option4: As with Option3 but enforcing it to use Option Strict On for its overload resolution and its conversion to IFormattable/FormattableString. 165 | 166 | RESOLUTION: Option3. 167 | 168 | 169 | 170 | Q. What about delegate relaxation level of $"hello" to FormattableString/IFormattable ? 171 | ```vb 172 | Sub f(lambda as Func(Of FormattableString)) 173 | Sub f(lambda as Func(Of String)) 174 | f(Function() $"hello") 175 | ``` 176 | RESOLUTION: From the principle above, we'd like this to pick the String overload. The way to accomplish this is to classify the lambda conversion as DelegateRelaxationLevelReturnWidening. 177 | 178 | 179 | 180 | Q. What about full-width characters? 181 | e.g. does $"{{" give the non-full-width string "{" even if the two source characters had different widths? 182 | e.g. can you write $"{p}" where the open is wide and the close is normal width? 183 | e.g. there is no escape to put a full-width {, similar to how there's no escape to put a full-width " ? 184 | 185 | RESOLUTION: Yes that's all fine. 186 | 187 | 188 | 189 | --- 190 | 191 | These are the workitems left to do... 192 | 193 | C#: additionally report error message about bad factory 194 | C#: verify (add a test case) that user-defined and intrinsic conversions on string really are used for interpolated strings. 195 | VB: change array literal dominant type stuff 196 | VB: all the dominant type stuff 197 | VB: fix up delegate relaxation level to be widening (and write test for it) 198 | 199 | -------------------------------------------------------------------------------- /meetings/2015/README.md: -------------------------------------------------------------------------------- 1 | # Visual Basic .NET Language Design Notes for 2015 2 | 3 | Overview of meetings and agendas for 2015 4 | 5 | 6 | ## Jan 14, 2015 7 | 8 | [Visul Basic .NET Design Meeting Notes for Jan 14, 2015](LDM-2015-01-14-VB.md) 9 | 10 | Overload Resolution for String Interpolation 11 | 12 | -------------------------------------------------------------------------------- /meetings/2016/LDM-2016-05-06-VB.md: -------------------------------------------------------------------------------- 1 | # VB Design Notes for May 6, 2016 2 | 3 | # Agenda 4 | - ByRef Returns 5 | - Tuples 6 | 7 | ## ByRef Returns 8 | 9 | Today, functions and properties may only return values. This feature allows them to return references to storage locations. This is legal in the CLR with some constraints. 10 | 11 | Proposal is that we focus exclusively on the consumption scenario. The primary use-case for declaring members which return ByRef will be specialized collection classes (such as slice) that will almost certainly be written in C# and by a small number of people. It’s very valuable for VB users to be able to use such collection types but without more compelling use cases the production scenario has too much design baggage. Specifically, how to reconcile VB’s copy-in-copy out semantics for properties passed ByRef with returning properties ByRef. 12 | 13 | Further, I propose we add no new syntax or take a reference to a storage location, or create a ByRef local. This would limit the use of such collection types to exactly the scenarios supported today by arrays with exactly the same usage syntax. 14 | 15 | ### Decisions 16 | - Do we need special syntax to assign a reference to a ByRef local? 17 | 18 | No. 19 | - What if there’s a read-write property that takes a ByRef ‘value’ in its setter? 20 | 21 | We never call the setter. 22 | 23 | ``` VB.NET 24 | ' This will always assign the value at the location returned from the method to the location returned from the property. 25 | objA.ByRefReturningProperty = objB.ByRefReturningMethod() 26 | ``` 27 | - What does the IDE show when you invoke a member with a ByRef return? Maybe nothing, as we do for arrays? 28 | 29 | ``` VB.NET 30 | ' Signature of ArraySlice(Of Integer).Item 31 | Default Public ReadOnly Property Item(index As Integer) As ByRef Integer 32 | ``` 33 | 34 | Something like that. The IDE team synthesizes invalid syntax for scenarios like this all the time (e.g. indexed properties in C# Metadata-as-source). 35 | - Passing a ByRef return to a late-bound method call? 36 | 37 | ``` VB.NET 38 | ' Where M returns a ByRef. We must copy-back. 39 | obj.LateBoundCall(M()) 40 | ``` 41 | 42 | Make it work. 43 | - Assigning a late-bound property with a ByRef return. 44 | 45 | Doesn’t work. 46 | ## Tuples 47 | 48 | Tuples allow multiple values, potentially of different types, to be bundled up and passed around as a unit. This is primarily a platform interop feature so all decisions regarding the mutability of the tuple type, how the names of its members are persisted and read from metadata, how equality is computed, and the names and structure of the underlying tuple types are as decided in the C# LDM. 49 | ### Decisions 50 | - What is the syntax for a tuple type with names? 51 | 52 | ``` VB.NET 53 | Dim p As (x As Integer, y As Integer) 54 | ``` 55 | - What is the syntax for a tuple type without names? 56 | 57 | ``` VB.NET 58 | Dim p As (Integer, Integer) 59 | ``` 60 | - Can I use this syntax in any ‘As’ clause where a type could appear today? 61 | Yes. 62 | - Can attributes be applied to tuple element types? If so, how would this be persisted? 63 | 64 | ``` VB.NET 65 | Function GetFormatStringAndArgs() As (formatString As String, args As Object()) 66 | ``` 67 | 68 | No. 69 | - When a tuple type appears as the return type of a function or property, are the names of its elements in scope inside the body of the function or property? 70 | 71 | ``` VB.NET 72 | ' Multiple return values 73 | Function GetMinMax(numbers As Integer()) As (min As Integer, max As Integer) 74 | If numbers Is Nothing OrElse numbers.Length = 0 Then Return (0, 0) 75 | 76 | min = numbers(0) 77 | max = numbers(0) 78 | 79 | For i = 1 To numbers.Length - 1 80 | Dim n = numbers(i) 81 | 82 | If n < min Then min = n 83 | If n > max Then max = n 84 | Next 85 | End Function 86 | 87 | ' This feels like idiomatic VB. 88 | ``` 89 | 90 | One major issue is that the parameter names and return variable names would share a namespace so this would be an error: 91 | 92 | ``` VB.NET 93 | ' Multiple return values 94 | Function Pair(Of T1, T2)(first As T1, second As T2) As (first As T1, second As T2) 95 | Return (first, second) 96 | End Function 97 | 98 | ' Of course, since we're adding tuples to the language no one will ever write this method. 99 | ``` 100 | 101 | Counter-proposal: Auto “With” the return variable so you can use .min and .max in the scope of the function. 102 | 103 | Let's table this until we get more user/dogfooding feedback. We'll soon know whether this is essential our not. 104 | - How are tuple types convertible to one another? 105 | 106 | They are element-wise convertible. The conversion is a widening conversion if and only if each element conversion is a widening conversion and narrowing if any conversion is narrowing. 107 | Same warnings for name mix-ups, case-insensitive name comparisons (of course). 108 | - What's the impact on the late-binder? 109 | 110 | We might need to update the late-binder to support tuple conversions but not for tuple names. Lot of work and so many plot holes as names are associated with declarations, not values. This will also be a problem in the debugger since tuple names won't be there at runtime in many scenarios. 111 | - What is the syntax for a tuple literal expression without names? 112 | 113 | ``` VB.NET 114 | M((0, 0)) 115 | ``` 116 | - What is the syntax for a tuple literal expression with names? 117 | 118 | ``` VB.NET 119 | M((x:=0, y:=0)) 120 | ``` 121 | - Can you specify tuple elements out of order with named arguments? 122 | 123 | ``` VB.NET 124 | M((x:=0, y:=0)) 125 | ``` 126 | 127 | No. 128 | - Do we infer names for the tuple elements as we do for anonymous type members? 129 | 130 | ``` VB.NET 131 | Dim x = 0, y = 0 132 | Dim p = (x, y) 133 | ' Names inferred from initializer. 134 | WriteLine($"{p.x}, {p.y}") 135 | ``` 136 | 137 | No, as that would make it too difficult to make a tuple with no names. 138 | - How are tuple literals classified in the spec? 139 | 140 | Initially type-less, but reclassified as values after target-typing/type-inference. Analogous to array literals. 141 | 142 | ``` VB.NET 143 | ' The type of the literal is (Integer, Integer), not (String, String) 144 | Dim p As (Integer, Integer) = ("0", "0") 145 | ``` 146 | - What should the SemanticModel.GetSymbolInfo in target typing scenarios? 147 | 148 | ``` VB.NET 149 | ' The type of the literal is (Integer, Integer), not (String, String) 150 | Dim p As (x As Integer, y As Integer) = (x:=0, z:=0) 151 | ``` 152 | 153 | If you bind 'x' in the 'x:=' it should bind as a _reference_ to the x element of the tuple, not a definition. Likewise binding 'z' should bind as would a named argument which does not refer to any parameter defined on that method. Basically, tuple expression names _always_ refer to elements declared elsewhere, either explicitly or implicitly, but are never considered definitions on their own. This means that z:= in this case is an error since (x As Integer, y As Integer) does not define any element z. 154 | - Is there a special syntax for decomposing a tuple into separate variables? 155 | 156 | ``` VB.NET 157 | Dim (x, y) = GetPoint() 158 | For Each (x, y) In GetPoints() 159 | From (x, y) In GetPoints() 160 | Let (x, y) = GetPoint() 161 | Select (x, y) = GetPoint() ' Can’t actually do this, breaking change. 162 | 163 | ' Question: Superfluous parentheses seem not very VB-ish. 164 | ``` 165 | 166 | Yes, but they need parenthesis. Resolves some ambiguities, such as the last example, which would be a breaking change. 167 | - Is there a special syntax for decomposing a tuple into separate values and assigning those values to multiple l-values? 168 | 169 | ``` VB.NET 170 | (x, y) = GetPoint() 171 | ``` 172 | 173 | Probably. Though it will be the first time a statement in VB can begin with anything other than a keyword, an identifier, or a number. 174 | - Can operators “distribute” over tuple members provided the operator is defined on all members? 175 | 176 | ``` VB.NET 177 | Dim location = (0, 0) 178 | Dim acceleration = (1, 2) 179 | For i = 1 To 3 180 | location += acceleration 181 | Next 182 | ' location = (3, 6) 183 | ``` 184 | 185 | Cute but nope. 186 | - Is it OK that tuple returns don’t allow naming return values but inferring return types for functions, properties, and multi-line lambdas. 187 | 188 | ``` VB.NET 189 | ' By default in VB, you can specify the name and shape of APIs without specifying any types. 190 | Class C 191 | Private V 192 | Property P 193 | Sub S(a, ByRef b, Optional c = Nothing) 194 | End Sub 195 | Function F() 196 | End Function 197 | End Class 198 | 199 | ' This is already broken with Async and Iterator methods 200 | Async Function FAsync() 201 | Iterator Function EnumerateF() 202 | 203 | root.ReplaceNodes(Function(original, rewritten) As (final, triviaPolicy) 204 | ' ... 205 | final = AddStuff(rewritten) 206 | triviaPolicy = TriviaPolicy.Preserve 207 | End Function) 208 | 209 | ' Do we think this might be valuable in scripting? 210 | ``` 211 | 212 | The (Type1, Type2) syntax is too compelling. It's much more likely to want to define a tuple with no names than one with inferred or dynamic types.  213 | -------------------------------------------------------------------------------- /meetings/2016/README.md: -------------------------------------------------------------------------------- 1 | # Visual Basic .NET Language Design Notes for 2016 2 | 3 | Overview of meetings and agendas for 2016 4 | 5 | 6 | ## May 5, 2016 7 | 8 | [Visul Basic .NET Design Meeting Notes for May 5, 2016](LDM-2016-05-06.md) 9 | 10 | 1. ByRef Returns 11 | 2. Tuples 12 | -------------------------------------------------------------------------------- /meetings/2017/README.md: -------------------------------------------------------------------------------- 1 | # Visual Basic .NET Language Design Notes for 2017 2 | 3 | Overview of meetings and agendas for 2017 4 | 5 | **April** 6 | * [12th](vbldm-notes-2017.04.12.md) 7 | * Proposal [#59](https://github.com/dotnet/vblang/issues/59): New conversion operator/syntax (`As Type`/`CVal`) 8 | 9 | **May** 10 | * [19th](vbldm-notes-2017.05.19.md) 11 | * Default Interface Implementations 12 | 13 | **August** 14 | * [9th](vbldm-notes-2017.08.09.md) 15 | * Issue [#37](https://github.com/dotnet/vblang/issues/37): Await in Catch/Finally 16 | * Non-trailing named arguments 17 | * [23rd](vbldm-notes-2017.08.23.md) 18 | * Scenario [#135](https://github.com/dotnet/vblang/issues/135): Late-binding without `Option Strict Off` 19 | * Proposal [#136](https://github.com/dotnet/vblang/issues/136): `Dynamic` pseudo-type 20 | * Proposal [#117](https://github.com/dotnet/vblang/issues/117): Method-scoped `Option` and `Imports` statements 21 | * Proposal [#137](https://github.com/dotnet/vblang/issues/137): Late-bound member-access expressions 22 | * Proposal [#43](https://github.com/dotnet/vblang/issues/43): Variable-scoped late-binding 23 | * Proposal [#106](https://github.com/dotnet/vblang/issues/106): Erased interfaces 24 | * Proposal [#152](https://github.com/dotnet/vblang/issues/152): `Out` arguments 25 | * [30th](vbldm-notes-2017.08.30.md) 26 | * Nullable reference types 27 | 28 | **September** 29 | * 27th 30 | 31 | **October** 32 | * 4th 33 | * [18th](vbldm-notes-2017.10.18.md) 34 | * Proposal [#101](https://github.com/dotnet/vblang/issues/101): JSON Literals 35 | * Pattern matching 36 | * Annotated types 37 | * Proposal [#184](https://github.com/dotnet/vblang/issues/184): Tagged String literals (Related [#27](https://github.com/dotnet/vblang/issues/27): Guid literals) 38 | * JSON types for JSON IntelliSense 39 | * XML types for XML IntelliSense 40 | * Proposal [#190](https://github.com/dotnet/vblang/issues/190): `Try` assignment 41 | 42 | **November** 43 | * [15th](vbldm-notes-2017.11.15.md) 44 | * Proposal [#195](https://github.com/dotnet/vblang/issues/195) - `Static` Property Variables 45 | * Proposal [#196](https://github.com/dotnet/vblang/issues/196) - Implicit Property Backing Fields 46 | * Proposal [#197](https://github.com/dotnet/vblang/issues/197) - Inferred `Set` Parameter Type 47 | * Scenario [#219](https://github.com/dotnet/vblang/issues/219) - Implementing INotifyPropertyChanged is Tedious 48 | * Proposal [#107](https://github.com/dotnet/vblang/issues/107) - Replaceable Members 49 | * Proposal [#198](https://github.com/dotnet/vblang/issues/198) - Bindable Classes and Properties 50 | * Proposal [#107](https://github.com/dotnet/vblang/issues/194) - `WithPropertyEvents` Modifier to Enable Easy INotifyPropertyChanged Implementations 51 | 52 | **December** 53 | * [6th](vbldm-notes-2017.12.06.md) 54 | * Proposal [#25](https://github.com/dotnet/vblang/issues/25) - Range `1 To 10 Step 2` Expressions 55 | * _Related: [#180](https://github.com/dotnet/vblang/issues/180) - For-loop should use larger type to avoid overflow exception_ 56 | * Proposal [#215](https://github.com/dotnet/vblang/issues/215) - Allow Attributes on Generic Type Parameters 57 | * Proposal [#170](https://github.com/dotnet/vblang/issues/170) - New Tie-Breaker Rule for Resolving Ambiguity Between Overloads Which Differ By Refness of Arguments 58 | * Proposal [#218](https://github.com/dotnet/vblang/issues/218) - Expression tree rewrite for string comparison in VB should product an operator invocation, not a method call to Operators.CompareString 59 | * _Related: [#193](https://github.com/dotnet/vblang/issues/193) - Option Compare Ordinal (and OrdinalIgnoreCase?)_ 60 | * Proposal [#48](https://github.com/dotnet/vblang/issues/48) - Multiple `For` or `For Each` Control Variables Per Statement 61 | * _Related: [#104](https://github.com/dotnet/vblang/issues/104) - Extend `For Each` Statement with Query Comprehensions_ 62 | * Proposal [#186](https://github.com/dotnet/vblang/issues/48) - `Exit For j` Statement to Break Out of Nested `For` and `For Each` Loops 63 | * Proposal [#102](https://github.com/dotnet/vblang/issues/102) - Support Top-Level Statements in a Single Entry-Point File 64 | * Scenario [#219](https://github.com/dotnet/vblang/issues/219) - Implementing INotifyPropertyChanged is Tedious 65 | * Proposal [#107](https://github.com/dotnet/vblang/issues/107) - Replaceable Members 66 | * Proposal [#198](https://github.com/dotnet/vblang/issues/198) - Bindable Classes and Properties 67 | * Proposal [#107](https://github.com/dotnet/vblang/issues/194) - `WithPropertyEvents` Modifier to Enable Easy INotifyPropertyChanged Implementations 68 | -------------------------------------------------------------------------------- /meetings/2017/vbldm-notes-2017.04.12.md: -------------------------------------------------------------------------------- 1 | Agenda 2 | ====== 3 | 4 | - New conversion operator/syntax 5 | 6 | - GitHub repo review 7 | 8 | Guest attendee: Klaus Spoonman 9 | 10 | New conversion operator/syntax 11 | ============================== 12 | 13 | Scenario 14 | -------- 15 | 16 | Today VB has several casting syntaxes, each with subtle differences and performance implications. Nonetheless there are still some CLR conversions which are either inexpressible in VB or are only emitted with specific compilation options. 17 | 18 | ### CType Conversions 19 | 20 | CType is the all-around conversion operator supporting the widest set of conversions in the language. CType has several short-hand conversion operators in the language, e.g. CStr, CInt, that are just aliases for CType with intrinsic destination types, e.g. CType(…, String). Depending on the situation CType may emit a single IL instruction, a method call, or a combination. 21 | 22 | CType supports the following conversion types: 23 | 24 | - Runtime conversions 25 | 26 | - Boolean -> Integer (True = -1) 27 | 28 | - Unboxing conversion 29 | 30 | - Reference conversions (upcasts/downcasts) 31 | 32 | - Numeric conversions 33 | 34 | - Integral <-> Integral (opcode) 35 | 36 | - Floating point -> Integral (Math.Round) 37 | 38 | - Nullable conversions 39 | 40 | - String conversions (Char <-> String, Char() <-> String) 41 | 42 | - User-defined conversion operators 43 | 44 | - Other language conversions 45 | 46 | CType does not support the following conversion types: 47 | 48 | - Integer <-> Char (AscW, ChrW) 49 | 50 | - Truncation 51 | 52 | - Unchecked integral conversion (chopping) 53 | 54 | Additionally CType will always behave like DirectCast for type parameter conversions. 55 | 56 | ### DirectCast Conversions 57 | 58 | DirectCast supports native reference conversions only. 59 | 60 | Proposal 1 61 | ---------- 62 | 63 | 64 | 65 | As Type 66 | ------- 67 | 68 | - Runtime conversions 69 | 70 | - Boolean -> Integer (True = -1) (error) 71 | 72 | - Unboxing conversion 73 | 74 | - Reference conversions (upcasts/downcasts) 75 | 76 | - Numeric conversions 77 | 78 | - Integral <-> Integral (opcode) 79 | 80 | - Floating point -> Integral (Math.Round) 81 | 82 | - Nullable conversions 83 | 84 | - String conversions (Char <-> String, Char() <-> String) 85 | 86 | - User-defined conversion operators 87 | 88 | - Other language conversions 89 | 90 | TryCast like behavior – return null? Odd to throw sometimes and return null sometimes. 91 | 92 | (T)obj -> Cast obj 93 | 94 | obj as T -> TryCast(obj, T) 95 | 96 | Proposal 2 97 | ---------- 98 | 99 | Magic method fix – emit special code for CInt(Math.Round(*floating-point*)) and CInt(Math.Truncate(*floating-point*)) and CInt(Int/Fix(*floating-point*)) 100 | 101 | Proposal 3 102 | ---------- 103 | 104 | Expand DirectCast to support native numeric conversions *but not* user-defined conversions. 105 | 106 | Proposal 4 107 | ========== 108 | 109 | Checked/Unchecked is orthogonal 110 | 111 | Update TryCast to convert to nullable value types. 112 | 113 | CVal(value, T) only for numeric types and enumerations and char. 114 | 115 | GitHub repo review 116 | ================== 117 | -------------------------------------------------------------------------------- /meetings/2017/vbldm-notes-2017.05.19.md: -------------------------------------------------------------------------------- 1 | # Visual Basic Language Design Meeting Notes - 2017.05.19 2 | 3 | ## Agenda 4 | * Default Interface Implementations 5 | 6 | ## Discussion 7 | 8 | ### Default Interface Implementations 9 | 10 | #### Q: Are there any syntactic ambiguities around default interface implementations in VB? In C# a definition with a body or without one can be determined by the presence or absence of a semicolon. 11 | 12 | **Follow-up: Need to look at parser and come back.** 13 | 14 | #### Modifiers 15 | 16 | | Modifier | C# | VB | Notes | 17 | | -------------------------------------------- | --- | ---- | ----- | 18 | | Overridable (virtual) | Allowed, implied if there is a body | Same | | 19 | | MustOverride (abstract) | Implied if (not static or private) and there is no body | Same | | 20 | | NotOverridable (sealed) | Implied for static and private | Same | It's not permitted to make a NotOverridable Overrides. Means "non virtual" | 21 | | Public/Private/Friend | Allowed with normal meaning | Same | | 22 | | Protected/Friend Protected/Private Protected | Allowed, but meaning is implementation specific | | | 23 | 24 | #### Allowed members in interfaces with bodies 25 | 26 | | Member | C# | VB | Notes | 27 | | ------ | --- | --- | ----- | 28 | | Instance methods | Yes | | | 29 | | Shared methods | Yes | | | 30 | | Instance fields | **No** | | | 31 | | Shared fields | Yes | | | 32 | | Instance constructors | No | | | 33 | | Shared constructors | TBD | | | 34 | | Instance finalizers | No | | | 35 | | Instance properties | Yes, but not auto | | | 36 | | Shared properties | Yes, auto is TBD | | | 37 | | Default properties (indexers) | N/A | Same as other properties | | 38 | | Instance events | Yes, but must be Custom | | Should have same restrictions as in classes (private `RaiseEvent`) | 39 | | Shared events | Yes, auto is TBD | | | 40 | | Nested types | Yes | Yes | | 41 | | Operators | TBD | | | 42 | | Conversion operators | No | Same | | 43 | 44 | **Follow-up: Verify event behavior makes sense with regard to WinRT events.** 45 | 46 | #### Q: Do we allow `Implements` clause? 47 | 48 | ``` VB.NET 49 | Interface IBase 50 | 51 | Sub M() 52 | 53 | End Interface 54 | 55 | Interface IDerived 56 | Inherits IBase 57 | 58 | ~~Overridable Sub N() Implements IBase.M~~ 59 | 60 | ~~End Sub~~ 61 | 62 | NotOverridable Sub N() Implements IBase.M 63 | 64 | End Sub 65 | End Interface 66 | ``` 67 | 68 | **Yes**. `NotOverridable` allowed and implied. 69 | 70 | #### What does `MyClass` do in an interface? 71 | Nothing special; it allows non-virtual calls. 72 | 73 | #### Q: Should we allow or forbid implicit interface implementations (like C#) now? 74 | Because of the way the CLR looks up interface implementations (by name), if an interface declares an overridable member _and_ an implementor declares or inherits a public `Overridable`/`Overrides` member of the same name it will implicitly be picked up as the implementation/override of that interface member. 75 | 76 | **Options** 77 | * Make it an error 78 | * Recognize behavior (because we don't have a choice) 79 | * Allow `Overridable` or `MustOverride` methods to implement (interface members with bodies). 80 | 81 | **Decision Let's make it an error for now and evaluate implicit interface implementations separately.** 82 | -------------------------------------------------------------------------------- /meetings/2017/vbldm-notes-2017.08.09.md: -------------------------------------------------------------------------------- 1 | # Visual Basic Language Design Meeting - 2017.08.09 2 | 3 | ### Agenda 4 | * Await in Catch/Finally 5 | * Non-trailing named arguments 6 | 7 | ## Await in Catch/Finally 8 | 9 | **Differences from C#** 10 | 11 | VB allows jumping (`goto`) from the `Catch` block. 12 | 13 | ``` VB.NET 14 | Dim retryCount = 0 15 | Try 16 | retry: 17 | Catch ex As Exception When retryCount < 3 18 | retryCount += 1 19 | GoTo retry 20 | End Try 21 | ``` 22 | 23 | Decision: The feature is approved in principle but needs its priority driven by other platform changes such as `IAsyncDisposable/Async Using`. 24 | 25 | ## Non-Trailing Named Arguments 26 | 27 | ### Attributes 28 | Because in VB named argument syntax does not correspond to constructor arguments but field/property initialization this is not permitted in attribute. 29 | 30 | ``` VB.NET 31 | 32 | ``` 33 | 34 | ### Late-Binding 35 | Late-bound method invocations which have non-trailing named arguments raise a compile-time error. 36 | 37 | Action: Make sure we produce an error _after_ overload-resolution, not making method groups inapplicable. 38 | -------------------------------------------------------------------------------- /meetings/2017/vbldm-notes-2017.08.23.md: -------------------------------------------------------------------------------- 1 | # Visual Basic Language Design Meeting 2 | August 23rd, 2017 3 | 4 | ## Agenda 5 | * Late-binding without `Option Strict Off` 6 | * `Dynamic` pseudo-type 7 | * Method-scoped `Option` and `Imports` statements 8 | * Late-bound Member-Access expressions 9 | * Variable-scoped late-binding 10 | * Erased interfaces 11 | * `Out` arguments 12 | * Pipe-forward (`->`) operator 13 | 14 | ## `Dynamic` pseudo-type 15 | 16 | Feels like it could be a light-weight solution. 17 | 18 | Q: What's the stack-ranking on this feature? 19 | 20 | Q: Is it just a safe alias for `Object` or is it more like C# `dynamic` in that it always late-binds even if a static member is available. 21 | 22 | ## Method-scoped `Option` and `Imports` statements 23 | 24 | Q: Do we really want `Imports`? Seems kinda crazy. 25 | Could be useful, should break it out into another proposals. 26 | 27 | Between this and a `Dynamic` type, I like this better. 28 | 29 | This could dove-tail with an `Option Checked`. 30 | 31 | `Option`/`End Option` block. Blocked-scoped support types and namespaces in with block 32 | 33 | ## Late-bound Member-Access expressions 34 | 35 | ! means so much. 36 | 37 | There's a feature here, but it might not add its weight. 38 | The JSON thing is great. Oh, but it already works with ! so all the value just evaporated. 39 | 40 | ## Erased interfaces 41 | 42 | Needs more design 43 | 44 | ## `Out` Arguments 45 | 46 | Investigate C# -> VB -> C# and C# -> VB -> VB 47 | 48 | New warning on a VB override 49 | 50 | Recognize the OutAttribute, require no In. 51 | Don't add an Out argument modifier 52 | Out parameter separately. 53 | 54 | -------------------------------------------------------------------------------- /meetings/2017/vbldm-notes-2017.08.30.md: -------------------------------------------------------------------------------- 1 | # Visual Basic Language Design Meeting - 2017.08.30 2 | 3 | ### Agenda 4 | * Nullable reference type 5 | 6 | ## Nullable reference types 7 | Not ready yet. Revisit after the C# Prototype is released and we have more user feedback and concrete design decisions. Also, the damnit operator `!` conflicts with both VBs dictionary-access operator `dict!key` and the type character for single-precision floating-point numbers `Dim radius!` so we'll have to resolve that. 8 | -------------------------------------------------------------------------------- /meetings/2017/vbldm-notes-2017.10.18.md: -------------------------------------------------------------------------------- 1 | # Visual Basic Language Design Meeting 2 | October 18th, 2017 3 | 4 | ### Agenda 5 | * Proposal [#101](https://github.com/dotnet/vblang/issues/101): JSON Literals 6 | * Pattern matching 7 | * Annotated types 8 | * Proposal [#184](https://github.com/dotnet/vblang/issues/184): Tagged String literals (Related [#27](https://github.com/dotnet/vblang/issues/27): Guid literals) 9 | * JSON types for JSON IntelliSense 10 | * XML types for XML IntelliSense 11 | * Proposal [#190](https://github.com/dotnet/vblang/issues/190): `Try` assignment 12 | 13 | ## Proposal [#101](https://github.com/dotnet/vblang/issues/101) - JSON Literals 14 | 15 | JSON is the _lingua franca_ of the cloud. First-class JSON support could be a strong attractant for first-time developers. The power of copy/paste/modify to jump start a project can't be overstated. 16 | 17 | ``` VB.NET 18 | Dim dow = 19 | { 20 | "name": NameOf(DayOfWeek), 21 | "type": "enum", 22 | "subtype": GetType(DayOfWeek).GetEnumUnderlyingType().Name, 23 | "members": [ 24 | (From f In GetType(DayOfWeek).GetFields(Reflection.BindingFlags.Public Or Reflection.BindingFlags.Static) 25 | Select {f.Name: CInt(f.GetValue(Nothing))}) 26 | ] 27 | } 28 | ``` 29 | 30 | **Feedback** 31 | * If you want a top-level array we should drop the square brackets; the above code reads like "member" should be a one-element array whose first element is another array. 32 | * The explicit syntax does allow interleaving fixed and generated elements in the list, but is that scenario worth it? 33 | * Embedded syntax, should there be any special syntax like XML's `<%= %>`? _No strong feelings_. 34 | * "I like that it's so close to a general dictionary init syntax that it may be better thought of as that" - I would say that new dictionary - followed by that syntax it should work. It could be a superset of JSON. 35 | * The problem is the nested case. How do we know the List type? Do you restate the type or have a separate list syntax. 36 | 37 | ### JSON Pattern Matching? 38 | Related: [#139](https://github.com/dotnet/vblang/issues/139) - XML Patterns 39 | 40 | I think the principle for making a new "literal" or construction pattern is when the ceremony of creating an object(-graph) obscures the structure of the data itself. Therefore, I proposal the principle for introducing a pattern is when the ceremony of _inspecting_ and object(-graph) obscures the structure of the data. 41 | 42 | I haven't actually heard feedback that `.`, `!`, `.<>`, `.@`, and `...<>` obscure the structure of the underlying data when inspecting homogeneous collections. Therefore I believe the motivating example for any specialized patterns for JSON or XML would be dispatching over multiple possible structures nested within a larger one: 43 | 44 | ``` VB.NET 45 | For Each contact In account!contacts 46 | Select Case contact 47 | Case Match { "type": "business", 48 | "company_name": company, 49 | "address": address } 50 | 51 | ' Handling for businesses. 52 | 53 | Case Match { "type": "individual", 54 | "email": email } 55 | 56 | ' Handling for individuals. 57 | 58 | Case Match { "type": "government", 59 | "agency": agency, 60 | "jurisdiction": jurisdiction } 61 | 62 | ' Handle government agency. 63 | 64 | End Select 65 | Next 66 | ``` 67 | 68 | In the above example, each possible contact kind has different content. Inspecting and dispatching correctly would greatly obscure the actual structure of the data. 69 | 70 | * Decision: Table, wait for feedback/scenarios and more matching. 71 | 72 | ## Annotated types 73 | 74 | ### Proposal [#184](https://github.com/dotnet/vblang/issues/184) 75 | Related: [#27](https://github.com/dotnet/vblang/issues/27) - GUID Literals 76 | 77 | After discussing the scenario for GUID literals with customers I don't believe they are necessary. There isn't a good case to be made for an expression typed as `System.Guid` as the dominant use case (attributes) can only take compile-time/CLR constants, i.e. strings. The only notable benefit I've heard from users is _validation_. This naturally leads one to consider an analyzer. The problem with the analyzer approach today is that 1) such an analyzer must inspect every string literal in the program, 2) such an analyzer would have to determine if a erroneously typed string were _intended_ to be a GUID before validating it. 78 | 79 | A simple general solution is a syntax that lets a user decorate a (magic) string literal with a bit of metadata. This metadata would (like a comment) have absolutely no effect on compilation. It would however make it trivial for a set of validation analyzers to target string literals _intended_ for validation _and_ to know what validation is required. 80 | 81 | Example: 82 | 83 | ``` VB.NET 84 | ? "{123e4567-e89b-12d3-a456-426655440000}"#Guid 85 | ``` 86 | 87 | In all ways such an annotated string literal would behave exactly as a string literal does today and the set of annotation identifiers would be open-ended. However, illustrative examples include: GUIDs, dates, URIs, IP addresses, paths, database connection strings, and format strings. 88 | 89 | **Feedback** 90 | * Using attributes would be better than a special tag. 91 | * Attribute should be on the producing APIs rather than the strings themselves. The advantage is that everyone can benefit without changing their code. 92 | * Can you apply attributes to constants? 93 | * Could this be done with an analyzer? Does IOperation have the perf it needs to do this? _Test it_. 94 | 95 | **Bullets dodged** 96 | * **Discussion**: If the compiler understood annotations it could preserve them through type-inference at least. 97 | * **Question**: Could we add semantics that are generalizable? In a manner, nullable and tuple names are "annotations" applied to an underlying type. They enable us to report certain warnings, particularly around implicit conversions when, for example, element names are mismatched. Could be valuable in general to report conversion warnings between strings with different annotations or strings with and without annotations? 98 | * **Question**: Could this be further generalized to annotating any type? 99 | 100 | ## XML and JSON 101 | 102 | Is there an even richer notion of an annotated type which could be used to add and track simple information about XML and JSON literals to better enable the IDE to provide completion when using XML-axis properties or the dictionary-access operator? 103 | 104 | ``` VB.NET 105 | Dim x As ' Type: 106 | Dim y = x.
' Type: .
107 | Dim z = y..Value 108 | ``` 109 | 110 | ``` VB.NET 111 | Dim a As {"contact"} ' Type: {"contact"} 112 | Dim b = a!address ' Type: {"contact"}.{"address"} 113 | Dim c = b!city 114 | ``` 115 | 116 | **Feedback** 117 | * This is one end of the spectrum of providing a better tooling experience for untyped data over the wire. Type providers are on the other end. 118 | * We might be able to do a lot with no compiler changes and should investigate with IDE team. 119 | 120 | ## Proposal [#190](https://github.com/dotnet/vblang/issues/190) - `Try` assignment 121 | Related: [#175](https://github.com/dotnet/vblang/issues/175), [#159](https://github.com/dotnet/vblang/issues/159), [#132](https://github.com/dotnet/vblang/issues/132), [#67](https://github.com/dotnet/vblang/issues/67), [#60](https://github.com/dotnet/vblang/issues/60) 122 | 123 | **Feedback** 124 | * Are side-effects really that bad? 125 | * Syntax is weird because the right-hand side of the assignment can assign to the thing it's initializing; should it instead be forced to return a different value? 126 | * But how would we represent the case where a failed "Try" should result in throwing or early exit? 127 | * Swift accomplishes this design with `if let` for positive cases and `guard let` for negative cases. Might that be a better design to explore? 128 | -------------------------------------------------------------------------------- /meetings/2017/vbldm-notes-2017.11.15.md: -------------------------------------------------------------------------------- 1 | # Visual Basic Language Design Meeting 2 | November 15th, 2017 3 | 4 | ## Agenda 5 | * Proposal [#195](https://github.com/dotnet/vblang/issues/195) - `Static` Property Variables 6 | * Proposal [#196](https://github.com/dotnet/vblang/issues/196) - Implicit Property Backing Fields 7 | * Proposal [#197](https://github.com/dotnet/vblang/issues/197) - Inferred `Set` Parameter Type 8 | * Scenario [#219](https://github.com/dotnet/vblang/issues/219) - Implementing INotifyPropertyChanged is Tedious 9 | * Proposal [#107](https://github.com/dotnet/vblang/issues/107) - Replaceable Members 10 | * Proposal [#198](https://github.com/dotnet/vblang/issues/198) - Bindable Classes and Properties 11 | * Proposal [#107](https://github.com/dotnet/vblang/issues/194) - `WithPropertyEvents` Modifier to Enable Easy INotifyPropertyChanged Implementations 12 | 13 | ## Proposal [#195](https://github.com/dotnet/vblang/issues/195) - `Static` Property Variables 14 | 15 | **Decisions** 16 | * **Rejected**. We don't see why this one narrow use case for members nested within other members get's special treatment. If we want to enable nesting we'd look at local functions and types as well. 17 | 18 | ## Proposal [#196](https://github.com/dotnet/vblang/issues/196) - Implicit Property Backing Fields 19 | 20 | **Decisions** 21 | * **Rejected**. The design team found this idea deeply unsettling. 22 | 23 | ## Proposal [#197](https://github.com/dotnet/vblang/issues/197) - Inferred `Set` Parameter Type 24 | 25 | **Decisions** 26 | * **Approved-in-Principle**. 27 | 28 | **Discussion** 29 | 30 | Technically the entire parameter list on `Set` is already optional and we could get most of the value of this proposal by stopping the IDE from generating it because an implicit parameter named `Value` is created. We could just color it blue. But it's also fairly easy to just do the "inference" as when we're creating the setter `MethodSymbol` we already have the type of the property in hand. 31 | 32 | ## Scenario [#219](https://github.com/dotnet/vblang/issues/219) - Implementing INotifyPropertyChanged is Tedious 33 | 34 | These three proposals fall on a spectrum from most general (#107) to most specific (#198), with #194 falling somewhere in between. We 35 | 36 | Proposal #194 seems to strike a good balance. We like that it could support a few more scenarios than just `INotifyPropertyChanged`, e.g. logging, "Freezable" objects. How do we choose? 37 | 38 | * We know that we wouldn't want both `Bindable` properties and `WithPropertyEvents`; they're mutually exclusive. 39 | * We know that if we had either of the above that wouldn't stop us from doing `Replaces` w/ source generators at a future date. 40 | * We're fairly confident that if we had `Replaces` w/ source generators we wouldn't do `Bindable` or `WithPropertyEvents` as `INotifyPropertyChanged` is basically the poster child for the source generator feature. 41 | 42 | We need to know the status of source generators and how far out they are before deciding. We should investigate and revisit with findings in a future meeting. 43 | 44 | **Decisions** 45 | * **Investigate status of source generators and revisit in future meeting**. 46 | 47 | ### Proposal [#107](https://github.com/dotnet/vblang/issues/107) - Replaceable Members 48 | 49 | We don't know the status of this and source generators. We should investigate and come back with findings in future meeting. 50 | 51 | ### Proposal [#198](https://github.com/dotnet/vblang/issues/198) - Bindable Classes and Properties 52 | 53 | _"Are the savings of this over #194 just the IDE automatically generating the bridge method? If so, we should go with the more general feature and just generate the correct code by default if you implement `INotifyPropertyChanged`"_. 54 | 55 | ### Proposal [#194](https://github.com/dotnet/vblang/issues/194) - `WithPropertyEvents` Modifier to Enable Easy INotifyPropertyChanged Implementations 56 | 57 | Can see a few use-cases for this. You could imagine implementing a "freezable" type immutable class whose properties all throw if you try to set them after the object has been "frozen". Need a better modifier though. 58 | -------------------------------------------------------------------------------- /meetings/2017/vbldm-notes-2017.12.06.md: -------------------------------------------------------------------------------- 1 | # Visual Basic Language Design Meeting 2 | December 6th, 2017 3 | 4 | ## Agenda 5 | * Proposal [#25](https://github.com/dotnet/vblang/issues/25) - Range `1 To 10 Step 2` Expressions 6 | * _Related: [#180](https://github.com/dotnet/vblang/issues/180) - For-loop should use larger type to avoid overflow exception_ 7 | * Proposal [#215](https://github.com/dotnet/vblang/issues/215) - Allow Attributes on Generic Type Parameters 8 | * Proposal [#170](https://github.com/dotnet/vblang/issues/170) - New Tie-Breaker Rule for Resolving Ambiguity Between Overloads Which Differ By Refness of Arguments 9 | * Proposal [#218](https://github.com/dotnet/vblang/issues/218) - Expression tree rewrite for string comparison in VB should product an operator invocation, not a method call to Operators.CompareString 10 | * _Related: [#193](https://github.com/dotnet/vblang/issues/193) - Option Compare Ordinal (and OrdinalIgnoreCase?)_ 11 | * Proposal [#48](https://github.com/dotnet/vblang/issues/48) - Multiple `For` or `For Each` Control Variables Per Statement 12 | * _Related: [#104](https://github.com/dotnet/vblang/issues/104) - Extend `For Each` Statement with Query Comprehensions_ 13 | * Proposal [#186](https://github.com/dotnet/vblang/issues/48) - `Exit For j` Statement to Break Out of Nested `For` and `For Each` Loops 14 | * Proposal [#102](https://github.com/dotnet/vblang/issues/102) - Support Top-Level Statements in a Single Entry-Point File 15 | * Scenario [#219](https://github.com/dotnet/vblang/issues/219) - Implementing INotifyPropertyChanged is Tedious 16 | * Proposal [#107](https://github.com/dotnet/vblang/issues/107) - Replaceable Members 17 | * Proposal [#198](https://github.com/dotnet/vblang/issues/198) - Bindable Classes and Properties 18 | * Proposal [#107](https://github.com/dotnet/vblang/issues/194) - `WithPropertyEvents` Modifier to Enable Easy INotifyPropertyChanged Implementations 19 | 20 | ## Proposal [#25](https://github.com/dotnet/vblang/issues/25) - Range `1 To 10 Step 2` Expressions 21 | 22 | _Related: [#180](https://github.com/dotnet/vblang/issues/180) - For-loop should use larger type to avoid overflow exception_ 23 | 24 | This proposal was envisioned specifically for VB and from the `For` loop down, so to speak. Independently, [the C# Range proposal](https://github.com/dotnet/roslyn/blob/features/range/docs/features/range.md) was envisioned for C# and designed from `Span`/slices up. After this morning's C# LDM it's clear that we'll need to reconcile the two designs to make sure both languages can share `Range` types and inter-operate nicely. As this is likely our last LDM in either language for the rest of 2017 due to holiday/vacations, we will review the broader VB design in the new year. 25 | 26 | **Decisions** 27 | * **Speclet needed**. 28 | 29 | ## Proposal [#215](https://github.com/dotnet/vblang/issues/215) - Allow Attributes on Generic Type Parameters 30 | 31 | **Decisions** 32 | * **Approved-in-Principle**. This isn't on our backlog but provide it was of high quality we'd likely accept this as a community PR. 33 | 34 | ## Proposal [#170](https://github.com/dotnet/vblang/issues/170) - New Tie-Breaker Rule for Resolving Ambiguity Between Overloads Which Differ By Refness of Arguments 35 | 36 | **Decisions** 37 | * **Approved-in-Principle**. We will likely need to do this to protect VB customers from breaks when API authors retro-fit `in` (readonly reference) parameter overloads on to existing methods. 38 | 39 | ## Proposal [#218](https://github.com/dotnet/vblang/issues/218) - Expression tree rewrite for string comparison in VB should product an operator invocation, not a method call to Operators.CompareString 40 | 41 | _Related: [#193](https://github.com/dotnet/vblang/issues/193) - Option Compare Ordinal (and OrdinalIgnoreCase?)_ 42 | 43 | Eh, back compat concerns, trees, operators with methods, new VB runtime, fallbacks, LINQ providers should fix their stuff, CInt doesn't support binary literals or digit group separators, late-binding won't support the tie-breaker discussed in #170, needa solution. 44 | 45 | **Decisions** 46 | * **Speclet needed**. 47 | 48 | ## Proposal [#48](https://github.com/dotnet/vblang/issues/48) - Multiple `For` or `For Each` Control Variables Per Statement 49 | 50 | _Related: [#104](https://github.com/dotnet/vblang/issues/104) - Extend `For Each` Statement with Query Comprehensions_ 51 | 52 | VB already has a strong precedent for multiple consecutive statements/constructs of the same kind being combinable into a comma-separated list: `Imports`, `Dim`, `Next`, `From`, `Let`, `Case` (required in this case). 53 | 54 | **Decisions** 55 | * **Approved-in-Principle**. None of us could think of a good reason why this doesn't already work. Allowing the `For Each` case is virtually required by #104. 56 | 57 | ## Proposal [#186](https://github.com/dotnet/vblang/issues/48) - `Exit For j` Statement to Break Out of Nested `For` and `For Each` Loops 58 | 59 | The real motivator for this is that `Goto` is a code-smell and people want a less smelly solution to this problem. 60 | 61 | **Decisions** 62 | * **Approved-in-Principle, also do this for `Continue For` statement**. 63 | 64 | ### Discussion 65 | 66 | We use `Goto` all over the scanners and parsers in both languages and we don't feel bad about those uses because `Goto` seems the most appropriate way of expressing that control flow. And because you're going from a likely more descriptive label name to a likely brief control variable name this could actually be a less readable construct in many cases. But, VB already has a bit of a precedent here insofar as: 67 | 68 | 1. The programmer can specify the specific block they want to exit at any time, e.g. `Exit Do`, `Exit While` to jump out of an outer loop or even out of an outer block via `Exit Select`. 69 | 2. The `Next` statement already lets you specify multiple control variables to close multiple loops in one go. 70 | 71 | **Would it be better to have labeled loops like in Java?** 72 | 73 | Maybe, but doing the proposal doesn't preclude us doing what Java does later. And if your control variables are well named, e.g. `row` and `column` then requiring the programmer to label the entire loop might very well be redundant and people would complain about that. 74 | 75 | **Should we require or allow a comma-separated list of control variables like `Next`, e.g. `Continue For x, y`?** 76 | Seems reasonable 77 | 78 | **No**. In fact, for the `Continue` case that's not at all what's happening. One isn't continuing the inner loop _then_ continuing the outer one; one is simply skipping to the next iteration of the outer loop. 79 | 80 | ## Proposal [#102](https://github.com/dotnet/vblang/issues/102) - Support Top-Level Statements in a Single Entry-Point File 81 | 82 | Last time we discussed this proposal we decided to take a wait-and-see approach with https://try.dot.net/. Today they use the scripting dialect of C# by virtue of using the Scripting API but based on discussions with them it would be beneficial to have the simplicity of top-level statements in the language(s) proper. For one, it means that all of the documentation sites/pages that are making use of trydotnet are technically teaching a slightly different version of the language with slightly different semantics. Let's try to reconcile the standard and scripting dialects in the new year. 83 | 84 | **Decisions** 85 | * **Deferred to January 2018**. 86 | 87 | ## Scenario [#219](https://github.com/dotnet/vblang/issues/219) - Implementing INotifyPropertyChanged is Tedious 88 | 89 | In our last deign meeting (two weeks ago) we looked at these three proposals on a spectrum from most general (#107) to most specific (#198), with #194 falling somewhere in between. The decision in that meeting was to take another look at our implementation concerns with [Source Generators](https://github.com/dotnet/roslyn/blob/features/range/docs/features/generators.md) to see if we could scope it down in such a way that it was achievable in the VB 16/C# 8 timeframe. Nope. While we bounced ideas around on how to constrain the behavior of generators to minimize the complexity and performance concerns it still feels like a _long_ lead to get it right both in design and implementation and especially iteration with the community for feedback. We absolutely cannot rush full meta-programming solution and our plate is pretty full already with HUGE ticket items for the next major version that generators are extremely unlikely to fit in either developer-time or calendar-time. 90 | 91 | Proposal #194 seems to strike a good balance. We like that it could support a few more scenarios than just `INotifyPropertyChanged`, e.g. logging, "Freezable" objects. 92 | 93 | ### Proposal [#107](https://github.com/dotnet/vblang/issues/107) - Replaceable Members 94 | 95 | **Decisions** 96 | * **Deferred to next release**. 97 | 98 | ### Proposal [#198](https://github.com/dotnet/vblang/issues/198) - Bindable Classes and Properties 99 | 100 | **Decisions** 101 | * **Rejected**. 102 | 103 | ### Proposal [#194](https://github.com/dotnet/vblang/issues/194) - `WithPropertyEvents` Modifier to Enable Easy INotifyPropertyChanged Implementations 104 | 105 | **Decisions** 106 | * **Approved for prototype/speclet**. 107 | -------------------------------------------------------------------------------- /meetings/2018/README.md: -------------------------------------------------------------------------------- 1 | # Visual Basic .NET Language Design Notes for 2018 2 | 3 | Overview of meetings and agendas for 2018 4 | 5 | ## February 6 | 7 | * [7th](vbldm-notes-2018.02.07.md) 8 | * C# Issue [#1208](hhttps://github.com/dotnet/csharplang/issues/1208) - C# Design Notes for nullable reference types 9 | * Issue [#117](https://github.com/dotnet/vblang/issues/117) - Block-scoped Option Statements 10 | * Issue [#211](https://github.com/dotnet/vblang/issues/211) - Discussion / proposal: usage of any installed programming language 11 | * 14th No meeting 12 | * [21st](vbldm-notes-2018.02.21.md) 13 | * Community Update 14 | * Upgrade Project - Discussion 15 | * Private Protected - Discussion 16 | * Issue [#37 Champion "Await in Catch and Finally"](https://github.com/dotnet/vblang/issues/37) 17 | * Issue [#228 - Default property for reading and setting bit flags](https://github.com/dotnet/vblang/issues/228) (and others) 18 | * [C# proposal: Default interface methods](https://github.com/dotnet/csharplang/blob/master/proposals/default-interface-methods.md) 19 | * [28th](vbldm-notes-2018.02.28.md) 20 | * Implications of C# Range on Visual Basic 21 | * Issue [#37 -Champion "Await in Catch and Finally"](https://github.com/dotnet/vblang/issues/37) 22 | * C# Issue [#967 Proposal for tuple equality/inequality comparisons](https://github.com/dotnet/csharplang/pull/967) 23 | 24 | ## March 25 | 26 | * Missed March 7 and 14 27 | * [21th](vbldm-notes-2018.03.21.md) 28 | * MVP Summit recap 29 | * Issue #86 [Optimize conversions from calls to Int/Fix functions and System.Math methods known to return whole Single/Double values to native opcodes](https://github.com/dotnet/vblang/issues/86) 30 | * Issue #280 [Can The Visual Basic DLL Be Open Sourced?](https://github.com/dotnet/vblang/issues/280) 31 | * Issue #282 [An update from the Design Safari on the `INotifyPropertyChanged` scenario](https://github.com/dotnet/vblang/issues/282) 32 | * Anthony D. Green attended as a guest! 33 | 34 | ## May 35 | 36 | * [30th](vbldm-notes-2018.05.30.md) 37 | * Europe trip report, stability, possible survey 38 | * Issue labels (marking what we've reviewed) 39 | * Issue 305: In and Out operators 40 | * Issue 304: Select TypeOf 41 | * Issue 303: Null conditional operators for add/removeHandler 42 | * Issue 301: Modify how literal strings are parsed 43 | * Issue 167: Support for Return? construct 44 | 45 | ## June 46 | 47 | *[13th](vbldm-notes-2018.06.13.md) 48 | * Review process 49 | * Issues reviewed 50 | 51 | ## July-December 52 | 53 | * Issue review and Microsoft.VisualBasic.Runtime.dll planning 54 | 55 | ## December 56 | 57 | * [19th](vbldm-notes-2018.12.19.md) 58 | * Pattern Matching discussion/proposal from community 59 | -------------------------------------------------------------------------------- /meetings/2018/vbldm-notes-2018.02.07.md: -------------------------------------------------------------------------------- 1 | # Visual Basic Language Design Meeting 2 | February 7,2018 3 | 4 | ## Agenda 5 | * [C# Issue #1208 - C# Design Notes for nullable reference types](https://github.com/dotnet/csharplang/issues/1208) 6 | * [Issue #117 - Block-scoped Option Statements](https://github.com/dotnet/vblang/issues/117) 7 | * [Issue #211 - Discussion / proposal: usage of any installed programming language](https://github.com/dotnet/vblang/issues/211) 8 | 9 | ## C# Issue [#1208](hhttps://github.com/dotnet/csharplang/issues/1208) - C# Design Notes for nullable reference types 10 | 11 | ### Part 1: Implementing analysis 12 | 13 | C# has a prototype for "nullable reference types" which uses flow analysis to establish whether a reference is intended to allow null. 14 | 15 | The user opts in per assembly. For other than a greenfield project, this results in a wall of compiler warnings, the user then works through these to resolve. 16 | 17 | There are probably a significant number of VB (and C#) projects where retrofitting this behavior is not desirable. While these warnings are valuable, it's unclear how popular this feature will be. And it may feel like a "not VB" thing as we understand its usage. 18 | 19 | We'll postpone this until we understand the uptake in C#. 20 | 21 | ### Part 2: Marking an assemblies surface area with null intention 22 | 23 | If a project opts into nullable reference warnings, it assumes all values received from assemblies that do not opt in may contain nulls. 24 | 25 | There will be a technique for annotating assemblies' surface area for nullability. This is important for the .NET frameworks. It is not clear how this will work, and at least at the implementation level it won't be as simple as managing attributes. 26 | 27 | Implementing this would allow VB projects to express their nullability to C# projects, even if the VB project did not do null checks internally. 28 | 29 | It is possible that VB could add the emitting attributes based on a simpler attributing system 30 | 31 | We'll postpone this until we know how the framework will handle this scenario and how much interest there is in this cross language support. 32 | 33 | ## Issue [#117](https://github.com/dotnet/vblang/issues/117) - Block-scoped Option Statements 34 | _Related: [#255](https://github.com/dotnet/vblang/issues/255) - Localised Compiler Options_ 35 | 36 | These issues suggest being able to limit the scope of Option Strict to a smaller block than the file. 37 | 38 | This is a convenience feature. Options are set per file, not per class. This means that any code that needs looser Options could be refactored into another method and placed in a Partial class. 39 | 40 | Considering all the options 41 | 42 | * Option Strict: Would provide value, possible to do 43 | * Option Explicit: Not seeing value, difficult to do 44 | * Option Compare: Not seeing high value, could create confusing code 45 | * Option Infer: This doesn't really make sense to us 46 | 47 | Leaving these two issues open for now, and requesting info on why #255 is not a duplicate. 48 | 49 | ## Issue [#211](https://github.com/dotnet/vblang/issues/211) - Discussion / proposal: usage of any installed programming language 50 | 51 | Fantastic idea, and too hard to do. 52 | 53 | Lots of thought has gone into this over the years. It was considered in depth when Roslyn was designed, and has been considered since. It would require rewriting considerable parts of Roslyn. 54 | 55 | It could be simplified somewhat if each type declaration was fully in one language or another. But, it would still need a new compiler and significant IDE work. 56 | 57 | And that would still leave open resolution of the many differences between C# and Visual Basic. The easiest of these differences to visualize are case sensitivity and overloads resolution. 58 | 59 | After rethinking again, the previous assessment that this is not practical stands. 60 | 61 | We believe it is important to communicate this clearly to the community so that we can, move toward other tractable issues. We will not close the issue for now to allow further discussion. 62 | -------------------------------------------------------------------------------- /meetings/2018/vbldm-notes-2018.02.21.md: -------------------------------------------------------------------------------- 1 | # Visual Basic Language Design Meeting 2 | 3 | February 21,2018 4 | 5 | ## Agenda 6 | 7 | * Community Update 8 | * Upgrade Project - Discussion 9 | * Private Protected - Discussion 10 | * Issue [#37 -Champion "Await in Catch and Finally"](https://github.com/dotnet/vblang/issues/37) 11 | * Issue [#228 - Default property for reading and setting bit flags](https://github.com/dotnet/vblang/issues/228) (and others) 12 | * [C# proposal: Default interface methods](https://github.com/dotnet/csharplang/blob/master/proposals/default-interface-methods.md) 13 | 14 | ## Community Update 15 | 16 | ### Introduce? 17 | 18 | There has been a request by the community for people to introduce themselves. 19 | 20 | This will remain at the discretion of the individual. 21 | 22 | ### Brice & EF 23 | 24 | @BriceLam has volunteered (side project) to maintain a repository for the development of a generator so migrations and reverse engineering work with VB projects. 25 | 26 | Kathleen will help publicize. 27 | 28 | When the project nears completion, Kathleen will explore best permanent location with Brice and contributors. 29 | 30 | Yeah Brice! 31 | 32 | ### MVP Summit 33 | 34 | MVP Summit is March 5-8. 35 | 36 | #### Language Designers Panel 37 | 38 | Kathleen will represent VB on the Language Designers Panel. 39 | 40 | #### Lunch session 41 | 42 | There will be a lunch session on Visual Basic. Kathleen determined this odd time with Jeff to avoid placing it opposite a session with likely interest to VB developers. We assume all VB MVPs are also interested in other things. 43 | 44 | #### Hackathon 45 | 46 | Thursday (March 8) at the MVP Summit there will be an MVP Hackathon. 47 | 48 | Do we want to organize something? 49 | 50 | No, leave it to Brice on the EF generator and community for organization 51 | 52 | ### Docs 53 | 54 | There are some really out of date docs for VB and way too many docs for the docs teams to fix. 55 | 56 | Kathleen will discuss with the community and hopefully get some help with this. 57 | 58 | ### Blogpost with WebAPI example 59 | 60 | @KlausLoeffelmann is working on a blog post (with help from @obelink and others) that will illustrate VB working with a VB backend and an Angular front end. 61 | 62 | Kathleen is working planning other blog posts. 63 | 64 | ## Upgrade Project - Discussion 65 | 66 | The customer problem: To change the version of VB a project is targeting, you have to edit the .vbproj file. Ick. Extra Ick because VB programmers put high value on simplicity/low ceremony. 67 | 68 | The technical problem: 3-4 non-trivial features need to land to fix this. Want to do it, but won't be immediate. 69 | 70 | With the delay, do we hold feature announcements or apologize that people have to edit right now? 71 | 72 | Kathleen will corral the solution. 73 | 74 | Do not hold any announcements. The folks that want new features want them. 75 | 76 | ## Private Protected - Discussion 77 | 78 | Private protected specifies that a member is only visible from code that is both within the same assembly and within a derived class. 79 | 80 | The earlier decision was to parallel the IL names with VB styling and use FriendAndProtected and FriendOrProtected. FriendOrProtected would be a pretty listing fix for Protected Friend for symmetry. 81 | 82 | For context, in C# this feature was requested loudly by a few people. An agonizing and relatively extreme attempt at a better named and the community accepted that the feature by any name was better than no feature. Thus it is `private protected` in C#. 83 | 84 | Kathleen did not find an issue on this in VBLang. 85 | 86 | During implementation, we messed up. The feature was implemented in VB as `Private Protected` (in any order). The feature is currently present, but not announced. Because it is present, we will support `Private Protected` even if we did something else. 87 | 88 | Clearly the earlier decision was more VB like. But, very few people care about the feature, it exists right now in VB as `Private Protected`, and coders may hear about the concept via C# blogs so parallel naming may have one advantage. 89 | 90 | Decision: Stick with what we've got because we've got it. If people use the feature and there is a push for clearer naming, deal with it then. 91 | 92 | ## Issue [#37 - Champion "Await in Catch and Finally"](https://github.com/dotnet/vblang/issues/37) 93 | 94 | Partial discussion because @VSadov not present and he has the most history. 95 | 96 | This was considered for an earlier release, but we ran out of time. 97 | 98 | In general the work is similar to C#. But VB specific things, GoTo and OnError may make it more difficult. 99 | 100 | At least some of the challenging scenarios aren't legal in async methods anyway. 101 | 102 | GoTo and OnError seem unlikely in "modern" code that would use Async. Perhaps we could narrow the scenarios to simplify implementation. 103 | 104 | Reconsider with Vlad, probably next week. 105 | 106 | We should check that this is important and how much work before we commit. Kathleen will see if a prioritization survey at the Summit makes sense and there will be time. 107 | 108 | ## Issue [#228 - Default property for reading and setting bit flags](https://github.com/dotnet/vblang/issues/228) (and others) 109 | 110 | Flagged enums have challenges in both C# and VB. In VB they are rather painful. A solution at the API level would be great. 111 | 112 | An enum constraint by itself does not allow this to be solved via extension methods. Darn. 113 | 114 | Tabled for Kathleen to discuss with API team to see if this is on their radar. 115 | 116 | ## [C# proposal: Default interface methods](https://github.com/dotnet/csharplang/blob/master/proposals/default-interface-methods.md) 117 | 118 | C# has a proposal for default interface members. A compelling scenario for this involves allowing interfaces to change over time without breaking all implementors. The implication is that people will then evolve interfaces, and if VB can't handle this, it will have a serious problem. 119 | 120 | C# and Runtime are designed and prototyped (for C# 8 timeframe). The design is not set. 121 | 122 | There will still be issues with older compiler versions unable to access interfaces that have changed (C#/VB). So it's not clear how public interfaces will take advantage of this feature. 123 | 124 | Talk to @AnthonyDGreen for background. 125 | 126 | No action. -------------------------------------------------------------------------------- /meetings/2018/vbldm-notes-2018.02.28.md: -------------------------------------------------------------------------------- 1 | # Visual Basic Language Design Meeting 2 | 3 | February 28,2018 4 | 5 | ## Agenda 6 | 7 | * Implications of C# Range on Visual Basic 8 | * Issue [#37 -Champion "Await in Catch and Finally"](https://github.com/dotnet/vblang/issues/37) 9 | * C# Issue [#967 Proposal for tuple equality/inequality comparisons](https://github.com/dotnet/csharplang/pull/967) 10 | 11 | ## Community Update 12 | 13 | ### MVP Summit 14 | 15 | MVP Summit is March 5-8. 16 | 17 | ## Implications of C# Range on Visual Basic 18 | 19 | The C# LDM is discussing possibility adding operators to make range access easier. 20 | 21 | This is to support programs that will use some of the new .NET Core API features for direct memory access and manipulation. These aren't expected to be high usage workflows in VB, but we don't want to block VB programmers from those scenarios. 22 | 23 | The work to supply this feature will be about the same for Visual Basic, after the C# feature is specced. There is a high probability that there are more important features for VB. But, let's still take a look at syntax possibilities and more deeply at alternate approaches. 24 | 25 | ### Potential Syntax 26 | 27 | Since the hat is currently used as a binary operator, it would be available as a unary operator. 28 | 29 | `.:` could be used for length. 30 | 31 | Open ended `x..` and `..x` and `..` also work. 32 | 33 | The To as a Range separator would be weird if the range was exclusive as anticipated. Not using that. `..` would work. 34 | 35 | ``` 36 | Dim x = s.Slice(0..11) ' seems pretty VB like 37 | ``` 38 | 39 | We believe that there is non-trivial amounts of VB code that are imprecise about the length of arrays - Dimming with the length instead of 1 minus the length. Consistent usually would generally allow this code to work fine, but if we allow counting from the end, and code has an array one to long, things will not work as expected. Nothing we can do about that. 40 | 41 | Wait to see what C# does and whether we need syntax. 42 | 43 | ### Using API Support 44 | 45 | If index provides an implicit conversion from int, then VB can access the API. Or if integers are used, conversions to Range. 46 | 47 | ``` 48 | Index i = Index.FromEnd(Int32 i) 49 | 50 | Range = New Range(2, Index.FromEnd(2)) 51 | Dim z1 = Slice(Range) 52 | Dim z2 = Slice(New Range(2, Index.FromEnd(2)) 53 | 54 | Dim z3 = Slice(Range.StartAt(2)) 55 | Dim z4 = Slice(Range.Open) ' maybe Range.All 56 | Dim z5 = Slice(Range.EndAt(8)) 57 | Dim z6 = Slice(Range.FromEnd(2)) 58 | ``` 59 | 60 | It might be even cooler if there are conversions from tuples. 61 | 62 | ``` 63 | ' Conversion from tuple of Index or integer 64 | Dim z7 = Slice((2,3)) 65 | Dim s8 = Slice((2,Index.FromEnd(2))) 66 | ``` 67 | 68 | If the API support is good enough, don't do the language work in VB. These APIs will allow older versions of Visual Basic (and C#) access these APIs and may come out reading more "VB like" than the dot dot range syntax. 69 | 70 | If we can't get good enough for VB users, then reconsider. 71 | 72 | Kathleen will discuss possibilities for API with API folks. 73 | 74 | NOTE: Following discussions with Immo on 3/1. 75 | 76 | The API already has methods of the style discussed here. They do not have final names, so at the point that is firmed up, we can ensure it makes sense for VB. Conversions are possible, although Immo thought it was weird to go just one direction with the conversion and Range to Integer tuple is probably not sensible. 77 | 78 | ## Issue [#37 -Champion "Await in Catch and Finally"](https://github.com/dotnet/vblang/issues/37) 79 | 80 | In VB you can't Await in a Catch block. This makes it pretty much impossible to do some things after an exception that we assume user's would like to do. The language is blocking these scenarios, so can we fix it. 81 | 82 | @VSadov was present so we can complete last week's discussion. 83 | 84 | Await in try catch is implemented by rewriting the code to use a complex state machine. 85 | 86 | It is legal in VB (but not C#) to jump from inside a Catch to inside the Try. Await in catch in C# was implemented without support for this (obviously), and we aren't quite sure how to do it because nested Try/Catch create some interesting possibilities. 87 | 88 | If we drop the difficult scenarios and provide support and disallow Await and these jumps to happen together, this is doable. 89 | 90 | Let's do it! 91 | 92 | Kathleen to discuss resourcing. 93 | 94 | ## C# Issue [#967 Proposal for tuple equality/inequality comparisons](https://github.com/dotnet/csharplang/pull/967) 95 | 96 | Tuple equality is being considered for C#. Given that x and y are tuples 97 | 98 | ```VB 99 | If x.Equals(y) Then ' works today if they are of the same type 100 | 101 | ' The following is not supported 102 | If x = y Then ' in general probably means... 103 | If x.First = y.First AndAlso x.Second = y.Second Then 104 | ``` 105 | 106 | Equality operator is a convenient and a manner of nicer style. 107 | 108 | Since the equality operator more different than Equals. It is not a reference equals, for example. Nullable value types also works some place in VB where it doesn't in C#. 109 | 110 | This is likely to need different deep thought than C# (more than a port) to find VB behavior (quirks in a good way). 111 | 112 | Much of the work in the feature comes when the types are different. Most of the value to the programmer occur when the types are the same. 113 | 114 | Ran out of time to complete. 115 | -------------------------------------------------------------------------------- /meetings/2018/vbldm-notes-2018.03.21.md: -------------------------------------------------------------------------------- 1 | # Visual Basic Language Design Meeting 2 | 3 | March 21, 2018 4 | 5 | ## Agenda 6 | 7 | * MVP Summit recap 8 | * Issue #86 [Optimize conversions from calls to Int/Fix functions and System.Math methods known to return whole Single/Double values to native opcodes](https://github.com/dotnet/vblang/issues/86) 9 | * Issue #280 [Can The Visual Basic DLL Be Open Sourced?](https://github.com/dotnet/vblang/issues/280) 10 | * Issue #282 [An update from the Design Safari on the `INotifyPropertyChanged` scenario](https://github.com/dotnet/vblang/issues/282) 11 | 12 | Anthony D. Green attended as a guest! 13 | 14 | ## MVP Summit recap and poll discussion 15 | 16 | We were able to communicate that helping with documentation counts as OSS contributions for MVP status and that testing is also considered. Need more work to track testing, but definitely issues raised on GitHub. 17 | 18 | Work was done on the EF Visual Basic generators at the Hackathon. This continues for now in [@BriceLam 's repo](https://github.com/bricelam/EFCore.VisualBasic) 19 | 20 | 21 | ## Issue #86 [Optimize conversions from calls to Int/Fix functions and System.Math methods known to return whole Single/Double values to native opcodes](https://github.com/dotnet/vblang/issues/86) 22 | 23 | CInt and Fix call methods on System.Math, and are thus slow(ish). 24 | 25 | There are two issues, this addressed only the optimization. This does not effect or comment on considering syntax enhancements. 26 | 27 | People that are currently using CInt(Fix()) want that optimized. While it seems slightly cryptic, it's the right way to get the truncated value and nothing else. This is what we can optimize. 28 | 29 | Treat it as an optimization, not a feature to keep it narrow and get it done. 30 | 31 | Probably some people that use CInt() probably don't care and do want optimization. But this is a breaking change and can't be done. 32 | 33 | Do we want an analyzer that finds slow CInts? It would change the semantics of the program. Probably won't do this. Folks might write this, that would be fine if they communicate usage. 34 | 35 | Maybe consider up-for-grabs once we have a proposal. 36 | 37 | Anthony has an analysis that he's going to send analysis that evaluates that results are identical. 38 | 39 | What about expression trees? 40 | 41 | Expression trees themselves will be unchanged. The IL output of expression trees is not expected to be high performance. Thus, plan to do what is easy. If code is shared, the optimization will also happen in the IL generation from expression trees. 42 | 43 | Neal will create an issue on Roslyn. 44 | 45 | ## Issue #280 [Can The Visual Basic DLL Be Open Sourced?](https://github.com/dotnet/vblang/issues/280) 46 | 47 | Is this a request to build a new VB runtime that is based on .NET Core and standard? 48 | 49 | Looking at a new layering. Those things forever typed to Windows can't be handled the same way as things that could be in standard. 50 | 51 | We'lll think further on this which needs discussion with the runtime folks. 52 | 53 | We need more information on the goals of this request. 54 | 55 | ## Issue #282 [An update from the Design Safari on the `INotifyPropertyChanged` scenario](https://github.com/dotnet/vblang/issues/282) 56 | 57 | We spent the rest of the meeting with Anthony's demo for affecting behavior using attributes and compile time rewriting. Overall impression was positive. 58 | 59 | ## Meetings 60 | 61 | We will miss next week's meeting due to Kathleen's travel. -------------------------------------------------------------------------------- /meetings/2018/vbldm-notes-2018.05.30.md: -------------------------------------------------------------------------------- 1 | # Visual Basic Language Design Meeting 2 | 3 | May 30, 2018 4 | 5 | We have been largely on break because of travel, Build and other issues. 6 | 7 | ## Agenda 8 | 9 | * Europe trip report, stability, possible survey 10 | * Issue labels (marking what we've reviewed) 11 | * Issue 305: In and Out operators 12 | * Issue 304: Select TypeOf 13 | * Issue 303: Null conditional operators for add/removeHandler 14 | * Issue 301: Modify how literal strings are parsed 15 | * Issue 167: Support for Return? construct 16 | 17 | ## Europe trip report, stability, possible survey 18 | 19 | We discussed stability, the current VB strategy and input I heard on my Europe trip. We believe the majority of Visual Basic customers (there are hundreds of thousands of quiet customers each month) primarily want VB to keep doing what it does now. It remains striking how few Visual Basic programmers we're able to hear from. We have a small group of important friends and a large number of silent users. We don't know what this larger group wants, they aren't asking us for features. 20 | 21 | We will discuss with folks at Microsoft that know about such things the possibility of a survey to try to gather better information. There is no plan to change the strategy, although we'll continue to discuss how we communicate it effectively so that people know Microsoft remains committed to Visual Basic. The survey needs to go to VB programmers only (not a Twitter survey) 22 | 23 | ## Issue labels 24 | 25 | Kathleen will put together a document for review that clarifies how we communicate our review of issues. Initial thoughts: 26 | 27 | * "LDM Reviewed: No plans" as opposed to closing or rejected to avoid shutting down further discussion but communicating that we don't plan to move forward 28 | * "LDM Thinking" 29 | * Orthogonally, group issues that are related to larger areas, such as "Pattern Matching" and "Flagged Enums" 30 | 31 | ## Issue #305 [In and Out operators](https://github.com/dotnet/vblang/issues/305) 32 | 33 | Considered in three pieces: 34 | 35 | ### In against a normal list (not types) 36 | 37 | This does not seem to have much value - is not significantly more expressive even if shorter - than .Contains against the list. Not moving forward for this reason. 38 | 39 | ### In against a list of types 40 | 41 | Kathleen's alternative syntax is wrong. TypeOf...Is is not an exact match, but whether a cast can occur. This is a concern with this feature since there is already some confusion around how TypeOf...Is. 42 | 43 | The correct syntax is a bit involved, but when would this be useful. You would branch, but would have to do additional casts. It seems much more likely that you'd do a series of If statements or similar. 44 | 45 | Not moving forward unless we see significant real world cases, and still have concerns. 46 | 47 | ### Out 48 | 49 | This is similar to Pattern Matching and Out variables in C#. Out variables are probably covered better in [#60](https://github.com/dotnet/vblang/issues/60) and pattern matching by [#124](https://github.com/dotnet/vblang/issues/124) 50 | 51 | Labels: Pattern Matching and LDM Reviewed: No Plans 52 | 53 | ## Issue #304 [Select TypeOf](https://github.com/dotnet/vblang/issues/304) 54 | 55 | Will consider part of pattern matching. 56 | 57 | Labels: Pattern Matching and LDM Reviewed: No Plans 58 | 59 | ## Issue #303 [Null conditional operators for add/removeHandler](https://github.com/dotnet/vblang/issues/303) 60 | 61 | As suggested this would only work if special case lowering or similar occurs because the null is more or less on the assignment side. 62 | 63 | Considered in relation to .NET 3 focus on WinForms/WPF. However, even in that context this would be quite rare (generally humans don't do the AddHandlers thing and generally all controls are instantiated.) 64 | 65 | Really seems like a side case. 66 | 67 | Labels: LDM Reviewed: No Plans 68 | 69 | ## Issue #301 [Modify how literal strings are parsed.](https://github.com/dotnet/vblang/issues/301) 70 | 71 | To summarize: Unicode is ugly. It's maybe a bit extra ugly in VB. 72 | 73 | We considered `\u3264`. VB has a bit of an advantage of C# here because it can avoid the `u`/`U` ugliness. We considered special casing in interpolated strings, but it seems more logical to just make it a literal if we did it. But it looks so not-VB! 74 | 75 | Considered variations with trailing type character like `&H3264c`. That's only nominally better than `ChrW`. People are likely to use constants if they want clarity. 76 | 77 | Labels: LDM Thinking 78 | 79 | ## Issue #167 [Proposal: Support for Return? construct](https://github.com/dotnet/vblang/issues/167) 80 | 81 | We flipped over to #167 while looking at #303. 82 | 83 | We think this is a bad idea. Control flow would be altered by a very subtle character. It's not the same meaning as other uses as ? (any alteration in control flow) 84 | 85 | Labels: LDM Reviewed: No Plans -------------------------------------------------------------------------------- /meetings/2018/vbldm-notes-2018.06.13.md: -------------------------------------------------------------------------------- 1 | # Visual Basic Language Design Meeting 2 | 3 | June 13, 2018 4 | 5 | Last week's meeting subsumed with other issues. 6 | 7 | ## Agenda 8 | 9 | * Review process 10 | * Issues reviewed 11 | 12 | ## Review process 13 | 14 | We'll review issues and use one of the following labels 15 | 16 | * **LDM In Process**: LDM review is in progress 17 | * **LDM Considering**: LDM reviewed and think this has merit 18 | * **LDM No Plans**: LDM reviewed and this feature is unlikely to move forward in the foreseeable future(*) 19 | * **LDM Rejected**: LDM reviewed and rejected 20 | 21 | (*) This is the description we decided after our first description didn't have as much transparency as we intended. 22 | 23 | We will begin reviewing with issues that have been quiet for a couple of months. Our goals with this is not to disrupt active conversations. 24 | 25 | We will put our logic in the issue itself, not in the meeting notes as we think it will be more accessible. 26 | 27 | A few notes on our overall thinking: 28 | 29 | * We will almost never make breaking changes to Visual Basic (often resulting in _Rejected_ label) 30 | * There may be some extreme edge cases that we believe highly unlikely ever 31 | * We may be forced, and we will do everything to avoid being forced 32 | * We are just beginning planning for .NET Core 3 version of Visual Basic, but currently anticipate a very high bar for breaking changes. 33 | * We strongly believe that Visual Basic has a stance - a way of doing things. We will strive to maintain consistency with things being "VB-like" (often resulting in a No Plans or rejected label) 34 | * Our observation is that the vast majority of Visual Basic users are not asking for us for new features so our bar for expansion of the surface area - making a second way to do things - will be relatively high even when it's a good idea (often resulting in a _No Plans_ label) 35 | * Consistent with the [Visual Basic language strategy](https://blogs.msdn.microsoft.com/dotnet/2017/02/01/the-net-language-strategy/) C# will take the lead on some issues - particularly those that would involve changes to the CLR or .NET libraries. We'll note this and suggest discussion in [CSharpLang](https://github.com/dotnet/csharplang) 36 | 37 | # Reviewed 38 | 39 | Logic for the decisions are included in comments adjacent to the label change for these issues 40 | 41 | **No Plans**: 42 | * [#47](https://github.com/dotnet/vblang/issues/47) 43 | * [#256](https://github.com/dotnet/vblang/issues/256) 44 | * [#272](https://github.com/dotnet/vblang/issues/272) 45 | * [#244](https://github.com/dotnet/vblang/issues/244) 46 | * [#62](https://github.com/dotnet/vblang/issues/62) 47 | * [#229](https://github.com/dotnet/vblang/issues/229) 48 | 49 | **Rejected**: 50 | * [#288](https://github.com/dotnet/vblang/issues/288) 51 | 52 | -------------------------------------------------------------------------------- /meetings/2018/vbldm-notes-2018.12.19.md: -------------------------------------------------------------------------------- 1 | # Visual Basic Language Design Meeting 2 | 3 | December 19, 2018 4 | 5 | Last week's meeting subsumed with other issues. 6 | 7 | ## Agenda 8 | 9 | * Pattern Matching discussion/proposal from community 10 | 11 | It's been a while since we've had Language Design in our weekly meetings because folks on the LDM have been distracted with the VB runtime and have not been doing language work, since [it will be a while before we can implement new features](https://blogs.msdn.microsoft.com/vbteam/2018/11/12/visual-basic-in-net-core-3-0/). These realities and timeline haven't changed, but we had a fun meeting on pattern matching in relation to the [VBLang issue #337](https://github.com/dotnet/vblang/issues/337). 12 | 13 | In general, we like to watch community issues - our involvement can be "leading the witness" and potentially miss exploring an avenue. In this case, the conversation had made significant progress and it was a good time to review, and it was requested. 14 | 15 | It was really gratifying that we started with the initial issue and early comments, then had a very free-wheeling discussion on what it might look like, then found our conclusions were in very close alignment with [this summary of the community conversation to date](https://github.com/dotnet/vblang/issues/337#issuecomment-448427815). Fantastic job by the community at VBLang looking at the problems from many directions. 16 | 17 | We all want to do pattern matching, it's the thing we are most excited about after C# interop issues. The time-frame we think is practical remains around VB.NET 16.2. And, while we are optimistic, like all such discussions, we are not making a commitment to doing this. 18 | 19 | For background: a pattern is not an expression, but a thing that when matched results in an expression, in this context a Boolean expression. 20 | 21 | ## Overall thoughts and criteria 22 | 23 | * No breaking changes. 24 | * Think ahead so the initial design doesn't box us away from things we might want later. 25 | * Where we need to make a decision, we will follow C# unless there is a compelling reason to avoid adding more subtle differences between the languages (many programmers work in C# and VB.NET). 26 | * Balancing the previous, we want pattern matching to be VB-like as possible - for example, C# restrictions regarding constant expressions may not be appropriate. 27 | * A phased release allows the community to understand concepts individually (this concept is not VB.NET specific, this was done in C#). The likely order (in separate, not necessarily sequential versions): 28 | * Declaration pattern - type match with assignment equivalent and When clause 29 | * Recursive patterns (including tuple patterns) 30 | * Maybe _and_ and _or_ and _not_ patterns later (still uncertain on this) 31 | 32 | ## Comments on summary posted Dec-18, 2018 33 | 34 | It seems most appropriate to structure our thoughts in relation to [this comment's summary](https://github.com/dotnet/vblang/issues/337#issuecomment-448427815). 35 | 36 | #1. Both `Matches` and `Is` were discussed. We think `Is` will have ambiguity issues with the existing use for reference equality. We might be able to finesse the use of `Is` with operators, by expanding thinking about what a pattern is, but other scenarios are more problematic. `Matches` is the proposed keyword. 37 | 38 | ```VB 39 | If o Matches x As String 40 | ' ... 41 | End If 42 | 43 | Select Case o 44 | Case x As String 45 | ' ... 46 | End Select 47 | ``` 48 | 49 | Not all of us are happy with the reading of the `If` syntax. The human English wording would be more like "If o matches string, put it in x as a string." While we didn't find an alternative in the meeting, we've since found [this suggestion by @AdamSpeight2008](https://github.com/dotnet/vblang/issues/119#issuecomment-313021036) which leads to considering the alternative: 50 | 51 | ```VB 52 | If o Matches String Into x 53 | ' ... 54 | End If 55 | 56 | Select Case o 57 | Case String Into x 58 | ' ... 59 | End Select 60 | ``` 61 | 62 | This will lead to a discussion about whether it is more important to read like English or to look like a declaration here. 63 | 64 | We are not ready for a negation pattern, but think that would work better than a `DoesntMatch` keyword. 65 | 66 | We agree that an additional keyword is not required in all `Case` cases, we haven't removed the possibility to remove ambiguity or to increase readibility. 67 | 68 | #2. We are a little confused. The effect of [#119](https://github.com/dotnet/vblang/issues/119#issue-239288726) seems desirable, but not sure whether this is a pattern or evaluation (or what distinctions matter here). 69 | 70 | #3. We thought about commas. If patterns are evaluated in certain scenarios, like method parameters, commas are a problem. For example, similar to a pattern in another thread was: 71 | 72 | ```VB 73 | Select Case o 74 | Case 1 To 10, 47 75 | ' stuff 76 | End Select 77 | ``` 78 | 79 | But this syntax can't be used as a method argument, because it would be unclear whether 47 is a pattern or a second argument. 80 | 81 | ```VB 82 | f(Matches 1 To 10, 47) 83 | ``` 84 | 85 | Our resolution was for the comma to remain a special feature of `Case`, not a part of the pattern syntax. 86 | 87 | This also results in a natural answer for whether When should apply to each part of a multi-part Case match. This syntax might be expressed like (whether or not parens are ultimately legal syntax here): 88 | 89 | ```VB 90 | Select Case o 91 | Case (x As String [When ]), (y As Object [When ]) 92 | ' ... 93 | End Select 94 | ``` 95 | 96 | Certainly everything that works in the context of a `Case` today should continue to work in a `Case`. But hesitate on moving syntax from `Case` to other places patterns can be used. 97 | 98 | #4. The linked "full range of potential patterns" is for F# and several of these are not available in other .NET languages. 99 | 100 | It's not clear how variable introduction without typechecking would work, or how type checking without assignment differs from the available `TypeOf x Is `. 101 | 102 | #5. We like `When`. 103 | 104 | #6. Can we get clarity on this. Is this basically saying there can't be ambiguity and we can't break existing code? 105 | 106 | #7. Do you mean `Case` should not require `Is` where it does not require it today? 107 | 108 | 8# i) We need some compelling cases for non-matches. The most compelling case for patterns is TypeCheck/assignment, and that doesn't seem to make sense for non-matches. 109 | 110 | #8 ii) If you mean exhaustiveness of cases in `Select Case`, we don't have this today and introducing it is backwards breaking. 111 | 112 | #8 iii) Need clarity on what this is saying 113 | 114 | #8 iv) Agree. We don't usually let variables be used before they are declared, so it would look quite weird to allow this in one case (`DoBottomLoopStatement`) 115 | 116 | ## Current state of the grammar 117 | 118 | We are very, very early in this process and this is open to a great deal of iteration, but the best current expression of the grammar is this, which is copied from [@zpitz summary of the community conversation here](https://github.com/dotnet/vblang/issues/337#issuecomment-448427815) with the changes noted: 119 | 120 | ``` 121 | // LDM: Throughout: "PatternExpression" has been replaced with "Pattern". 122 | // This probably needs a bit more work, because the implication is that 123 | // When is part of the pattern and some confusion in that part below. 124 | // The resolution needs to be clear that a pattern is not an expression. 125 | 126 | BooleanExpressionOrPattern 127 | : BooleanExpression 128 | | Expression 'Matches' Pattern 129 | ; 130 | 131 | 132 | // If...Then..ElseIf blocks 133 | // LDM: The scope of introduced variables is the surrounding scope 134 | 135 | BlockIfStatement 136 | : 'If' BooleanExpressionOrPattern 'Then'? StatementTerminator 137 | Block? 138 | ElseIfStatement* 139 | ElseStatement? 140 | 'End' 'If' StatementTerminator 141 | ; 142 | 143 | ElseIfStatement 144 | : ElseIf BooleanExpressionOrPattern 'Then'? StatementTerminator 145 | Block? 146 | ; 147 | 148 | LineIfThenStatement 149 | : 'If' BooleanExpressionOrPattern 'Then' Statements ( 'Else' Statements )? StatementTerminator 150 | ; 151 | 152 | 153 | // Loops 154 | // LDM thinks introduced variables scope to the While block 155 | WhileStatement 156 | : 'While' BooleanExpressionOrPattern StatementTerminator 157 | Block? 158 | 'End' 'While' StatementTerminator 159 | ; 160 | 161 | // introducing variables with either While or Until could only be used 162 | // by the When clause, not within the block 163 | // LDM thinks probably within the block as well 164 | DoTopLoopStatement 165 | : 'Do' ( WhileOrUntil BooleanExpressionOrPattern )? StatementTerminator 166 | Block? 167 | 'Loop' StatementTerminator 168 | ; 169 | 170 | // introducing variables with either While or Until could only be used 171 | // by the When clause, not within the block 172 | DoBottomLoopStatement 173 | : 'Do' StatementTerminator 174 | Block? 175 | 'Loop' WhileOrUntil BooleanExpressionOrPattern StatementTerminator 176 | ; 177 | 178 | ConditionalExpression 179 | : 'If' OpenParenthesis BooleanExpressionOrPattern Comma Expression Comma Expression CloseParenthesis 180 | | 'If' OpenParenthesis Expression Comma Expression CloseParenthesis 181 | ; 182 | 183 | 184 | // Within a Case clause 185 | 186 | CaseStatement 187 | : 'Case' Pattern StatementTerminator 188 | Block? 189 | ; 190 | What are the parts of a pattern expression? 191 | 192 | Pattern 193 | : Pattern ('When' BooleanExpression)? 194 | ; 195 | What patterns should be supported from the start? 196 | 197 | 198 | // LDM reworded: 199 | Multiple Patterns 200 | // multiple patterns are separately evaluated and each has it's own when clause 201 | // multiple patterns are only supported in case 202 | : Pattern ',' Pattern // OR pattern (already supported in Case) 203 | 204 | Patterns 205 | // LDM wants to understand need for TypeCheck without assignemnt. 206 | | 'As' TypeName // Type check pattern -- matches when subject is of TypeName 207 | // LDM wants to understand usage without type 208 | | 'Dim' Identifier ('As' TypeName)? // Variable pattern -- introduces a new variable in child scope; as TypeName or Object 209 | // LDM: Tentatively thinking of other Case syntax as a pattern may be useful, but these might remain specific to Case 210 | | 'Is'? ComparisonOperator Expression // Comparison pattern 211 | | 'Like' StringExpression // Like pattern 212 | | Expression 'To' Expression // Range pattern 213 | | Expression // Expression pattern -- value/reference equality test against Expression 214 | ; 215 | ``` 216 | 217 | ## Other Notes 218 | 219 | * What does "nested patterns" mean? Maybe not V1 220 | * `If obj Is String Then Console.WriteLine("obj is a string")` already available with `TypeOf..Is` 221 | * If we do _and_ and _or_ later, AndAlsoMatches/OrElseMatches is one option. Conjunctions are probably not in first or second version, C# thinking is these are much lower need/usage. 222 | * Probably add a discard identifier and a discard pattern 223 | -------------------------------------------------------------------------------- /meetings/README.md: -------------------------------------------------------------------------------- 1 | # Visual Basic .NET Language Design Meetings 2 | 3 | Visual Basic .NET Language Design Meetings (LDM for short) are meetings by the Visual Basic .NET Language Design Team and invited guests to investigate, design and ultimately decide on features to enter the Visual Basic .NET language. It is a creative meeting, where active design work happens, not just a decision body. 4 | 5 | Every Visual Basic .NET language design meeting is represented by a meeting notes file in this folder. 6 | 7 | ## Purpose of the meetings notes 8 | 9 | Meeting notes serve the triple purposes of 10 | 11 | - recording decisions so they can be acted upon 12 | - communicating our design thinking to the community so we can get feedback on them 13 | - recording rationale so we can return later and see why we did things the way we did 14 | 15 | All have proven extremely useful over time. 16 | 17 | ## Life cycle of meeting notes 18 | 19 | - If upcoming design meetings have a specific agenda, there may be a meeting notes file with that agenda even before the meeting happens 20 | - After the meeting notes will be saved directly here. 21 | - Usually they will be raw notes in need of subsequent cleaning up. If that's the case, they will be clearly marked as such, and a work item will track the task of cleaning up the notes. 22 | - When the notes are finalized, a notification is sent to the mailing list. Discussion can happen there. 23 | - If the notes impact current proposals, work items will track updating those proposals. 24 | - When updated, the proposals link back to the meeting where the proposal was discussed. 25 | 26 | ## Style of design notes 27 | 28 | The notes serve as the collective voice of the LDM. They cover not just the decisions but the discussion, options and rationale, so that others can follow along in the discussion and provide input to it, and so that we don't forget them for later. 29 | 30 | However, *the notes are not minutes*! They *never* state who said what in the meeting. They will occasionally mention people by name if they are visiting, provided input, should be collaborated with, etc. But the notes aim to represent the shared thinking of the room. If there's disagreement, they will report that, but they won't say who wants what. 31 | 32 | This approach is intended to reinforce that the LDMs are a safe space, and a collaborative, creative effort. It is not a negotiation between representatives of different interests. It is not a voting body, and it is not a venue for posturing. Everybody cooperates towards the same end: creating the best language for today's and tomorrow's Visual Basic .NET developers. 33 | 34 | -------------------------------------------------------------------------------- /meetings/notes-template.md: -------------------------------------------------------------------------------- 1 | # Visual Basic Language Design Meeting 2 | Month Day, Year 3 | 4 | ## Agenda 5 | * [Proposal #Number - Title](#proposal-number---title) 6 | * [Scenario #Number - Title](#scenario-number---title) 7 | 8 | ## Proposal [#Number](https://github.com/dotnet/vblang/issues/number) - Title 9 | _Related: [#Number](https://github.com/dotnet/vblang/issues/number) - Title_ 10 | 11 | ## Scenario [#Number](https://github.com/dotnet/vblang/issues/number) - Title 12 | _Related: [#Number](https://github.com/dotnet/vblang/issues/number) - Title_ 13 | 14 | ### Proposal [#Number](https://github.com/dotnet/vblang/issues/number) - Title 15 | _Related: [#Number](https://github.com/dotnet/vblang/issues/number) - Title_ 16 | -------------------------------------------------------------------------------- /proposals/README.md: -------------------------------------------------------------------------------- 1 | # VB Language Proposals 2 | 3 | Language proposals are living documents describing the current thinking about a give language feature. 4 | 5 | Proposals can be either *active*, *inactive*, *rejected* or *done*. *Active* proposals are stored directly in the proposals folder, *inactive* and *rejected* proposals are stored in the [inactive](proposals/inactive) and [rejected](proposals/rejected) subfolders, and *done* proposals are archived in a folder corresponding to the language version they are part of. 6 | 7 | ## Lifetime of a proposal 8 | 9 | A proposal starts its life when the language design team decides that it might make a good addition to the language some day. Typically it will start out being *active*, but if we want to capture an idea without wanting to work on it right now, a proposal can also start out in the *inactive* subfolder. Proposals may even start out directly in the *rejected* state, if we want to make a record of something we don't intend to do. For instance, if a popular and recurring request is not possible to implement, we can capture that as a rejected proposal. 10 | 11 | The proposal may start out as an idea on the mailing list, or it may come from discussions in the LDM, or arrive from many other fronts. The main thing is that the design team feels that it should be done, and that there's someone who is willing to write it up. 12 | 13 | A proposal is *active* if it is moving forward through design and implementation towards an upcoming release. Once it is completely *done*, i.e. an implementation has been merged into a release and the feature has been specified, it is moved into a subdirectory corresponding to its release. 14 | 15 | If a feature turns out not to be likely to make it into the language at all, e.g. because it proves unfeasible, does not seem to add enough value or just isn't right for the language, it will be *rejected*, and moved to the corresponding subfolder. If a feature has reasonable promise but is not currently being prioritized to work on, it is *inactive* and will be moved to the corresponding subfolder. It is perfectly fine for work to happen on inactive or rejected proposals, and for them to be resurrected later. The categories are there to reflect current design intent. 16 | 17 | ## Discussion of proposals 18 | 19 | Feedback and discussion happens on the VB design mailing list. When a new proposal is added, it should be announced on the mailing list. 20 | 21 | -------------------------------------------------------------------------------- /proposals/inactive/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotnet/vblang/0712f0b8c91dfba593fc16f846c5821ed5cad2f9/proposals/inactive/README.md -------------------------------------------------------------------------------- /proposals/overload-resolution-priority.md: -------------------------------------------------------------------------------- 1 | # Overload Resolution Priority 2 | 3 | ## Summary 4 | [summary]: #summary 5 | 6 | We introduced a new attribute, `System.Runtime.CompilerServices.OverloadResolutionPriority`, that can be used by API authors to adjust the relative priority of 7 | overloads within a single type as a means of steering API consumers to use specific APIs, even if those APIs would normally be considered ambiguous or otherwise 8 | not be chosen by overload resolution rules. See [Overload Resolution Priority in C#](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-13.0/overload-resolution-priority.md). 9 | 10 | ## Motivation 11 | [motivation]: #motivation 12 | 13 | API authors often run into an issue of what to do with a member after it has been obsoleted. For backwards compatibility purposes, many will keep the existing member around 14 | with `ObsoleteAttribute` set to error in perpetuity, in order to avoid breaking consumers who upgrade binaries at runtime. This particularly hits plugin systems, where the 15 | author of a plugin does not control the environment in which the plugin runs. The creator of the environment may want to keep an older method present, but block access to it 16 | for any newly developed code. However, `ObsoleteAttribute` by itself is not enough. The type or member is still visible in overload resolution, and may cause unwanted overload 17 | resolution failures when there is a perfectly good alternative, but that alternative is either ambiguous with the obsoleted member, or the presence of the obsoleted member causes 18 | overload resolution to end early without ever considering the good member. For this purpose, we want to have a way for API authors to guide overload resolution on resolving the 19 | ambiguity, so that they can evolve their API surface areas and steer users towards performant APIs without having to compromise the user experience. 20 | 21 | ## Detailed Design 22 | [detailed-design]: #detailed-design 23 | 24 | ### Overload resolution priority 25 | 26 | We define a new concept, ***overload_resolution_priority***, which is used during the process of overload resolution. ***overload_resolution_priority*** is a 32-bit integer 27 | value. All methods have an ***overload_resolution_priority*** of 0 by default, and this can be changed by applying 28 | [`OverloadResolutionPriorityAttribute`](#systemruntimecompilerservicesoverloadresolutionpriorityattribute) to a method. We update section 29 | [Overloaded Method Resolution](https://github.com/dotnet/vblang/blob/main/spec/overload-resolution.md#overloaded-method-resolution) of the VB specification as 30 | follows (change in **bold**): 31 | 32 | > 2. Next, eliminate all members from the set that are inaccessible or not applicable (Section [Applicability To Argument List](overload-resolution.md#applicability-to-argument-list)) to the argument list 33 | 34 | > **3. Then, the reduced set of candidate members is grouped by declaring type. 35 | > If the member is an override, the declaring type and the ***overload_resolution_priority*** come from the least-derived declaration of that member. 36 | > Within each group:** 37 | 38 | > - **A maximum ***overload_resolution_priority*** among candidates that do not utilize narrowing conversions or narrowing delegate relaxation is determined.** 39 | > - **All members that have a lower ***overload_resolution_priority*** than the maximum found during the previous step, if any, within its declaring type group are removed.** 40 | 41 | > **The reduced groups are then recombined into the set of candidates.** 42 | 43 | > **4**. Next, if one or more arguments are `AddressOf` or lambda expressions, then calculate the *delegate relaxation levels* for each such argument as below. If the worst (lowest) delegate relaxation level in `N` is worse than the lowest delegate relaxation level in `M`, then eliminate `N` from the set. The delegate relaxation levels are as follows: 44 | 45 | As an example, this feature would cause the following code snippet to print "I1", rather than failing compilation due to an ambiguity: 46 | 47 | ```vb 48 | Public Interface I1 49 | End Interface 50 | Public Interface I2 51 | End Interface 52 | Public Interface I3 53 | Inherits I1, I2 54 | End Interface 55 | 56 | Public Class C 57 | 58 | Public Shared Sub M(x As I1) 59 | System.Console.WriteLine("I1") 60 | End Sub 61 | Public Shared Sub M(x As I2) 62 | System.Console.WriteLine("I2") 63 | End Sub 64 | End Class 65 | 66 | Public Class Program 67 | Shared Sub Main() 68 | Dim i3 As I3 = Nothing 69 | C.M(i3) 70 | End Sub 71 | End Class 72 | ``` 73 | 74 | Negative numbers are allowed to be used, and can be used to mark a specific overload as worse than all other default overloads. 75 | 76 | The **overload_resolution_priority** of a member comes from the least-derived declaration of that member. **overload_resolution_priority** is not 77 | inherited or inferred from any interface members a type member may implement, and given a member `Mx` that implements an interface member `Mi`, no 78 | warning is issued if `Mx` and `Mi` have different **overload_resolution_priorities**. 79 | 80 | The candidates that utilize a narrowing conversion or a narrowing delegate relaxation are excluded from determining the maximum **overload_resolution_priority** 81 | because there is no guarantee that those candidates can be successfully invoked with the supplied arguments. 82 | For example, consider the following scenario: 83 | ``` vb 84 | Module Module1 85 | 86 | Sub Main() 87 | M1(New C0()) 88 | End Sub 89 | 90 | 91 | Sub M1(x As C1) 92 | End Sub 93 | 94 | Sub M1(x As C2) 95 | System.Console.Write(2) 96 | End Sub 97 | End Module 98 | 99 | Class C0 100 | Public Shared Narrowing Operator CType(x As C0) As C1 101 | Throw New System.InvalidCastException() 102 | End Operator 103 | Public Shared Widening Operator CType(x As C0) As C2 104 | Return New C2() 105 | End Operator 106 | End Class 107 | 108 | Class C1 109 | End Class 110 | 111 | Class C2 112 | End Class 113 | ``` 114 | 115 | When it is compiled with `Option Strict On`, `Sub M1(x As C1)` is not applicable because it cannot be called without a 116 | narrowing conversion. The only applicable candidate is `M1(x As C2)` and it is called. 117 | 118 | When the code is compiled with `Option Strict Off`, both methods are applicable. If the priority was given to `Sub M1(x As C1)`, 119 | a candidate that uses only widening conversions would be filtered out, resulting in an `InvalidCastException` thrown during execution. 120 | 121 | Here is another example: 122 | ``` vb 123 | Option Strict Off 124 | 125 | Module Module1 126 | 127 | Sub Main() 128 | M1(CObj(New C2())) 129 | End Sub 130 | 131 | 132 | Sub M1(x As I1) 133 | System.Console.Write(1) 134 | End Sub 135 | 136 | Sub M1(x As I2) 137 | System.Console.Write(2) 138 | End Sub 139 | End Module 140 | 141 | Interface I1 142 | End Interface 143 | 144 | Interface I2 145 | End Interface 146 | 147 | Class C2 148 | Implements I2 149 | End Class 150 | ``` 151 | 152 | In this case both candidates require narrowing conversion. Since filtering doesn't happen, the result of overload resolution 153 | is a late-bound invocation, which determines that `Sub M1(x As I1)` is inapplicable and invokes `Sub M1(x As I2)`. 154 | 155 | If the priority was given to `Sub M1(x As I1)` at compile time, it would remain the only applicable candidate and would be 156 | invoked early-bound, resulting in an `InvalidCastException` thrown during execution. 157 | 158 | ### `System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute` 159 | 160 | There is the following attribute in the BCL: 161 | 162 | ```cs 163 | namespace System.Runtime.CompilerServices; 164 | 165 | [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Property, AllowMultiple = false, Inherited = false)] 166 | public sealed class OverloadResolutionPriorityAttribute(int priority) : Attribute 167 | { 168 | public int Priority => priority; 169 | } 170 | ``` 171 | 172 | All methods and properties in VB have a default ***overload_resolution_priority*** of 0, unless they are attributed with `OverloadResolutionPriorityAttribute`. 173 | If they are attributed with that attribute, then their ***overload_resolution_priority*** is the integer value provided to the first argument of the attribute. 174 | 175 | By analogy with C#, it is an error to apply `OverloadResolutionPriorityAttribute` to the following locations: 176 | 177 | * Property, or event accessors 178 | * Conversion operators 179 | * Finalizers 180 | * Shared constructors 181 | * Overriding properties 182 | * Overriding methods 183 | 184 | Attributes encountered on these locations in metadata effectively will have no impact in VB code. 185 | 186 | ### Langversion Behavior 187 | 188 | Overload Resolution process does not perform filtering by ***overload_resolution_priority*** in VB < 17.13. 189 | No errors or warnings issued by the Overload Resolution process due to the fact that ***overload_resolution_priority*** 190 | was ignored in this case. 191 | 192 | By analogy with C#, a langversion error is issued when `OverloadResolutionPriorityAttribute` is applied in VB < 17.13. 193 | -------------------------------------------------------------------------------- /proposals/proposal-DerestrictedOperators.md: -------------------------------------------------------------------------------- 1 | # Derestricted Operators 2 | 3 | * [x] Proposed: [Complete](https://github.com/dotnet/vblang/issues/26) 4 | * [ ] Prototype: [Complete](https://github.com/PROTOTYPE_OWNER/roslyn/BRANCH_NAME) 5 | * [ ] Implementation: [In Progress](https://github.com/dotnet/roslyn/BRANCH_NAME) 6 | * [ ] Specification: [Not Started](pr/1) 7 | 8 | ## Summary 9 | [summary]: #summary 10 | 11 | Remove some of the restriction placed on operators. 12 | 13 | ## Motivation 14 | [motivation]: #motivation 15 | 16 | Under the current rules of the VB.net language, some operators require to be implementation in complement pairs. 17 | 18 | [] 19 | 20 | | Op | Comp | 21 | |----|----| 22 | | < | => | 23 | | <= | > | 24 | | > | <= | 25 | | >= | < | 26 | | <> | = | 27 | | = | <> | 28 | | IsTrue | IsFalse | 29 | | IsFalse | IsTrue | 30 | 31 | ```vb 32 | Public Shared Operator <( x As Foo, y As Foo) As Boolean 33 | 34 | End Sub 35 | 36 | Public Shared Operator >=( x As Foo, y As Foo) As Boolean 37 | 38 | End Sub 39 | ``` 40 | 41 | Or in proof of concept, commenting out the production of the error. 42 | ``` 43 | diagnostics.Add(ErrorFactory.ErrorInfo(ERRID.ERR_MatchingOperatorExpected2, 44 | SyntaxFacts.GetText(OverloadResolution.GetOperatorTokenKind(nameOfThePair)), 45 | method), method.Locations(0)) 46 | ``` 47 | 48 | 49 | --------------- 50 | ## Detailed design 51 | [design]: #detailed-design 52 | 53 | 54 | This proposal is to remove that restriction, by skip the following section of under a language feature conditional. 55 | [Source](https://github.com/dotnet/roslyn/blob/508c229005f4f6c556a54a78905971b1bc3bb9c7/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceMemberContainerTypeSymbol.vb#L3630) 56 | 57 | 58 | 59 | This is the bulk of the proposal. Explain the design in enough detail for somebody familiar 60 | with the language to understand, and for somebody familiar with the compiler to implement, and include examples of how the feature is used. This section can start out light before the prototyping phase but should get into specifics and corner-cases as the feature is iteratively designed and implemented. 61 | 62 | Example code: 63 | 64 | ```vbnet 65 | Module Module1 66 | 67 | Sub Main() 68 | Dim lower_limit = 0 69 | Dim upper_limit = 100 70 | Dim value_A = 50 71 | Dim value_B = -10 72 | Dim value_C = 180 73 | Dim res_A = lower_limit.__ < value_A <= upper_limit 74 | Dim res_B = lower_limit.__ < value_B <= upper_limit 75 | Dim res_C = lower_limit.__ < value_C <= upper_limit 76 | 77 | End Sub 78 | 79 | End Module 80 | 81 | Public Class CMPOP_A(Of T As IComparable(Of T)) 82 | 83 | Private _Value As T 84 | 85 | Sub New(value As T) 86 | _Value = value 87 | End Sub 88 | 89 | ' First part of Range Check is done here. Also note we have to remember what the middle value is over to the next part. 90 | Public Shared Operator <(x As CMPOP_A(Of T), y As T) As CMPOP_B(Of T) ' <-- Not a Boolean 91 | Return New CMPOP_B(Of T)(y, x._Value.CompareTo(y) < 0) 92 | End Operator 93 | 94 | Public Shared Operator <=(x As CMPOP_A(Of T), y As T) As CMPOP_B(Of T) ' <-- Not a Boolean 95 | Return New CMPOP_B(Of T)(y, x._Value.CompareTo(y) <= 0) 96 | End Operator 97 | 98 | End Class 99 | 100 | Public Class CMPOP_B(Of T As IComparable(Of T)) 101 | 102 | Private _Value As T 103 | Private _State As Boolean 104 | 105 | Sub New(Value As T, state As Boolean) 106 | _Value = Value 107 | _State = state 108 | End Sub 109 | 110 | ' If the State is False already it skips the comparison and returns False. 111 | Public Shared Operator <(x As CMPOP_B(Of T), y As T) As Boolean 112 | Return x._State AndAlso (x._Value.CompareTo(y) < 0) 113 | End Operator 114 | 115 | Public Shared Operator <=(x As CMPOP_B(Of T), y As T) As Boolean 116 | Return x._State AndAlso (x._Value.CompareTo(y) <= 0) 117 | End Operator 118 | 119 | End Class 120 | 121 | Public Module Exts 122 | 123 | Public Function __(Of T As IComparable(Of T))(value As T) As CMPOP_A(Of T) 124 | Return New CMPOP_A(Of T)(value) 125 | End Function 126 | End Module 127 | 128 | 129 | ``` 130 | 131 | When trying to use a now non-existent operator. 132 | 133 | eg 134 | ```vb 135 | Dim res_A = lower_limit.__ > value_A <= upper_limit 136 | ``` 137 | 138 | `Error BC30452 Operator '>' is not defined for types 'CMPOP_A(Of Integer)' and 'Integer'.` 139 | 140 | 141 | 142 | 143 | 144 | 145 | ## Drawbacks 146 | [drawbacks]: #drawbacks 147 | 148 | Why should we *not* do this? 149 | 150 | ## Alternatives 151 | [alternatives]: #alternatives 152 | 153 | Change the error, to a warning. 154 | 155 | ## Unresolved questions 156 | [unresolved]: #unresolved-questions 157 | 158 | What parts of the design are still TBD? -------------------------------------------------------------------------------- /proposals/proposal-Implicit-default-optional-parameters.md: -------------------------------------------------------------------------------- 1 | # Implicit Default Optional Parameters 2 | 3 | * [x] Proposed 4 | * [x] Prototype: [Complete](https://github.com/AdamSpeight2008/roslyn-AdamSpeight2008/tree/master_Feature_ImplicitDefaultOptionalParameter) 5 | * [x] Implementation: [In Progress](https://github.com/AdamSpeight2008/roslyn-AdamSpeight2008/tree/PostDev15_Feature_ImplicitDefaultOptionalParameters) 6 | * [ ] Unit Tests 7 | * [x] Code Diagnostic Tool. 8 | * [ ] Specification: [Not Started](pr/1) 9 | 10 | ## Summary 11 | [summary]: #summary 12 | Assume an implicit default value for optional parameter. 13 | 14 | ## Motivation 15 | [motivation]: #motivation 16 | 17 | Simplifies the type of the more common usage case, that of using the default value of the associated type as the default to value of the parameter. 18 | Eg `Foo(Optional size As String = Nothing)` to `Foo(Optional size As String)` 19 | 20 | ## Detailed design 21 | [design]: #detailed-design 22 | 23 | The grammar definition for an `Optional Parameter` is something similar to this. 24 | 25 | ``` 26 | OptionalParameter ::= "Optional" ParameterName Typing? DefaultToValue? 27 | Typing ::= "As" TypeIdentifier 28 | DefaultToValue ::= "=" ( "Nothing" | ConstantValue ) 29 | ``` 30 | 31 | **Examples** 32 | The following forms will be support by this proposal, which in essence the type of the optional parameter must be specified. 33 | ```vb.net 34 | Foo( Optional arg1 As String ) ' --> Foo( Optional arg1 As String = Nothing ) 35 | Foo( Optional arg2 As String = Nothing ) ' --> Foo( Optional arg2 As String = Nothing ) 36 | Foo( Optional arg4 As Integer ) ' --> Foo( Optional arg4 As Integer = Nothing ) 37 | Foo( Optional arg5 As Integer = 0 ) ' --> Foo( Optional arg5 As Integer = 0 ) 38 | Foo( Optional arg6 As Integer = 1 ) ' --> Foo( Optional arg6 As Integer = 1 ) 39 | ``` 40 | Optional Parameters that don't specify a will function as existing (where the type is defined to object). 41 | As not to introduce a breaking change. *(As pointed out by @AnthonyDGreen)* 42 | ```vb.net 43 | Foo( Optional arg0 ) ' --> Foo( Optional arg0 As Object = Nothing ) 44 | Foo( Optional arg3 = "" ) ' --> Foo( Optional arg3 As String = "" ) 45 | Foo( Optional arg7 = 7 ) ' --> Foo( Optional arg7 As Integer = 7 ) 46 | ``` 47 | 48 | 49 | ## Potential Usage 50 | [potential]: #potential 51 | Using the following code authored by @AnthonyDGreen 52 | ```VB.NET 53 | Imports System.Console 54 | Imports System.IO 55 | 56 | Module Program 57 | 58 | Sub Main() 59 | Dim log = New StringWriter() 60 | 61 | Dim nothingDefaultCount = 0, 62 | nonNothingDefaultCount = 0 63 | 64 | For Each filename In Directory.EnumerateFiles("", "*.vb", SearchOption.AllDirectories) 65 | Dim tree = VisualBasicSyntaxTree.ParseText(File.ReadAllText(filename)) 66 | 67 | Dim root = tree.GetRoot() 68 | 69 | For Each decl In root.DescendantNodes.OfType(Of ParameterSyntax) 70 | If decl.Default Is Nothing Then Continue For 71 | 72 | If decl.Default.Value.IsKind(SyntaxKind.NothingLiteralExpression) OrElse 73 | decl.Default.Value.IsKind(SyntaxKind.FalseLiteralExpression) OrElse 74 | decl.Default.Value.ToString() = "0" _ 75 | Then 76 | nothingDefaultCount += 1 77 | Else 78 | nonNothingDefaultCount += 1 79 | 80 | Dim text = decl.ToString() 81 | WriteLine(text) 82 | log.WriteLine(text) 83 | End If 84 | Next 85 | Next 86 | 87 | WriteLine(nothingDefaultCount) 88 | WriteLine(nonNothingDefaultCount) 89 | 90 | My.Computer.Clipboard.SetText(log.ToString()) 91 | End Sub 92 | End Module 93 | ``` 94 | Running it on my roslyn repo clone it reports that of all the optional parameter declarations in VB in Roslyn 2229 out of 2612 of them, or > 85% use the default value of the parameter type as the default value of the parameter. So your suggestion would clean up 85% of the uses of Optional in Roslyn. Sounds like value to me! 95 | 96 | ## Invariants 97 | [invariants]: #invariants 98 | 99 | The following invariants must be preserved to maintain compatibility with legacy / preexisting code. 100 | 101 | `CallerInfoAttributes` 102 | 103 | **Legacy** 104 | ```VB.net 105 | Imports System.Runtime.CompilerServices 106 | Module Module1 107 | 108 | Sub Main() 109 | Dim r = Foo() 110 | Console.WriteLine(r) 111 | End Sub 112 | 113 | Function Foo( Optional x As Integer = 0) As Integer 114 | Console.WriteLine(x) 115 | Return x 116 | End Function 117 | 118 | End Module 119 | ``` 120 | **With Feature** 121 | ```vb.net 122 | Imports System.Runtime.CompilerServices 123 | Module Module1 124 | 125 | Sub Main() 126 | Dim r = Foo() 127 | Console.WriteLine(r) 128 | End Sub 129 | 130 | Function Foo( Optional x As Integer) As Integer 131 | Console.WriteLine(x) 132 | Return x 133 | End Function 134 | 135 | End Module 136 | ``` 137 | **Output** 138 | ``` 139 | R=5 140 | X=5 141 | ``` 142 | 143 | 144 | 145 | 146 | ## Drawbacks 147 | [drawbacks]: #drawbacks 148 | 149 | Why should we *not* do this? 150 | 151 | ## Alternatives 152 | [alternatives]: #alternatives 153 | 154 | What other designs have been considered? What is the impact of not doing this? 155 | 156 | ## Unresolved questions 157 | [unresolved]: #unresolved-questions 158 | 159 | What parts of the design are still TBD? 160 | -------------------------------------------------------------------------------- /proposals/proposal-template.md: -------------------------------------------------------------------------------- 1 | # FEATURE_NAME 2 | 3 | * [x] Proposed 4 | * [ ] Prototype: [Complete](https://github.com/PROTOTYPE_OWNER/roslyn/BRANCH_NAME) 5 | * [ ] Implementation: [In Progress](https://github.com/dotnet/roslyn/BRANCH_NAME) 6 | * [ ] Specification: [Not Started](pr/1) 7 | 8 | ## Summary 9 | [summary]: #summary 10 | 11 | One para explanation of the feature. 12 | 13 | ## Motivation 14 | [motivation]: #motivation 15 | 16 | Why are we doing this? What use cases does it support? What is the expected outcome? 17 | 18 | ## Detailed design 19 | [design]: #detailed-design 20 | 21 | This is the bulk of the proposal. Explain the design in enough detail for somebody familiar 22 | with the language to understand, and for somebody familiar with the compiler to implement, and include examples of how the feature is used. This section can start out light before the prototyping phase but should get into specifics and corner-cases as the feature is iteratively designed and implemented. 23 | 24 | Example code: 25 | 26 | ```VB.NET 27 | ' Creates an IEnumerable object that goes from 1 to 10. 28 | Dim range = 1 To 10 29 | ``` 30 | 31 | ## Drawbacks 32 | [drawbacks]: #drawbacks 33 | 34 | Why should we *not* do this? 35 | 36 | ## Alternatives 37 | [alternatives]: #alternatives 38 | 39 | What other designs have been considered? What is the impact of not doing this? 40 | 41 | ## Unresolved questions 42 | [unresolved]: #unresolved-questions 43 | 44 | What parts of the design are still TBD? -------------------------------------------------------------------------------- /proposals/rejected/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotnet/vblang/0712f0b8c91dfba593fc16f846c5821ed5cad2f9/proposals/rejected/README.md -------------------------------------------------------------------------------- /spec/README.md: -------------------------------------------------------------------------------- 1 | Visual Basic Language Specification 2 | ===================================== 3 | __Version 11__ 4 | 5 | (This document is also available for download: [vb.pdf](http://ljw1004.github.io/vbspec/Visual%20Basic%20Language%20Specification.pdf?raw=true) and [vb.docx](http://ljw1004.github.io/vbspec/Visual%20Basic%20Language%20Specification.docx?raw=true)) 6 | 7 | * [Introduction](introduction.md#introduction) 8 | * [Grammar Notation](introduction.md#grammar-notation) 9 | * [Compatibility](introduction.md#compatibility) 10 | * [Lexical Grammar](lexical-grammar.md#lexical-grammar) 11 | * [Characters and Lines](lexical-grammar.md#characters-and-lines) 12 | * [Identifiers](lexical-grammar.md#identifiers) 13 | * [Keywords](lexical-grammar.md#keywords) 14 | * [Literals](lexical-grammar.md#literals) 15 | * [Separators](lexical-grammar.md#separators) 16 | * [Operator Characters](lexical-grammar.md#operator-characters) 17 | * [Preprocessing Directives](preprocessing-directives.md#preprocessing-directives) 18 | * [Conditional Compilation](preprocessing-directives.md#conditional-compilation) 19 | * [External Source Directives](preprocessing-directives.md#external-source-directives) 20 | * [Region Directives](preprocessing-directives.md#region-directives) 21 | * [External Checksum Directives](preprocessing-directives.md#external-checksum-directives) 22 | * [General Concepts](general-concepts.md#general-concepts) 23 | * [Declarations](general-concepts.md#declarations) 24 | * [Scope](general-concepts.md#scope) 25 | * [Inheritance](general-concepts.md#inheritance) 26 | * [Implementation](general-concepts.md#implementation) 27 | * [Polymorphism](general-concepts.md#polymorphism) 28 | * [Accessibility](general-concepts.md#accessibility) 29 | * [Type and Namespace Names](general-concepts.md#type-and-namespace-names) 30 | * [Variables](general-concepts.md#variables) 31 | * [Generic Types and Methods](general-concepts.md#generic-types-and-methods) 32 | * [Attributes](attributes.md#attributes) 33 | * [Attribute Classes](attributes.md#attribute-classes) 34 | * [Attribute Blocks](attributes.md#attribute-blocks) 35 | * [Source Files and Namespaces](source-files-and-namespaces.md#source-files-and-namespaces) 36 | * [Program Startup and Termination](source-files-and-namespaces.md#program-startup-and-termination) 37 | * [Compilation Options](source-files-and-namespaces.md#compilation-options) 38 | * [Imports Statement](source-files-and-namespaces.md#imports-statement) 39 | * [Namespaces](source-files-and-namespaces.md#namespaces) 40 | * [Types](types.md#types) 41 | * [Value Types and Reference Types](types.md#value-types-and-reference-types) 42 | * [Interface Implementation](types.md#interface-implementation) 43 | * [Primitive Types](types.md#primitive-types) 44 | * [Enumerations](types.md#enumerations) 45 | * [Classes](types.md#classes) 46 | * [Structures](types.md#structures) 47 | * [Standard Modules](types.md#standard-modules) 48 | * [Interfaces](types.md#interfaces) 49 | * [Arrays](types.md#arrays) 50 | * [Delegates](types.md#delegates) 51 | * [Partial types](types.md#partial-types) 52 | * [Constructed Types](types.md#constructed-types) 53 | * [Special Types](types.md#special-types) 54 | * [Conversions](conversions.md#conversions) 55 | * [Implicit and Explicit Conversions](conversions.md#implicit-and-explicit-conversions) 56 | * [Boolean Conversions](conversions.md#boolean-conversions) 57 | * [Numeric Conversions](conversions.md#numeric-conversions) 58 | * [Reference Conversions](conversions.md#reference-conversions) 59 | * [Array Conversions](conversions.md#array-conversions) 60 | * [Value Type Conversions](conversions.md#value-type-conversions) 61 | * [String Conversions](conversions.md#string-conversions) 62 | * [Widening Conversions](conversions.md#widening-conversions) 63 | * [Narrowing Conversions](conversions.md#narrowing-conversions) 64 | * [Type Parameter Conversions](conversions.md#type-parameter-conversions) 65 | * [User-Defined Conversions](conversions.md#user-defined-conversions) 66 | * [Native Conversions](conversions.md#native-conversions) 67 | * [Dominant Type](conversions.md#dominant-type) 68 | * [Type Members](type-members.md#type-members) 69 | * [Interface Method Implementation](type-members.md#interface-method-implementation) 70 | * [Methods](type-members.md#methods) 71 | * [Constructors](type-members.md#constructors) 72 | * [Events](type-members.md#events) 73 | * [Constants](type-members.md#constants) 74 | * [Instance and Shared Variables](type-members.md#instance-and-shared-variables) 75 | * [Properties](type-members.md#properties) 76 | * [Operators](type-members.md#operators) 77 | * [Statements](statements.md#statements) 78 | * [Control Flow](statements.md#control-flow) 79 | * [Local Declaration Statements](statements.md#local-declaration-statements) 80 | * [With Statement](statements.md#with-statement) 81 | * [SyncLock Statement](statements.md#synclock-statement) 82 | * [Event Statements](statements.md#event-statements) 83 | * [Assignment Statements](statements.md#assignment-statements) 84 | * [Invocation Statements](statements.md#invocation-statements) 85 | * [Conditional Statements](statements.md#conditional-statements) 86 | * [Loop Statements](statements.md#loop-statements) 87 | * [Exception-Handling Statements](statements.md#exception-handling-statements) 88 | * [Branch Statements](statements.md#branch-statements) 89 | * [Array-Handling Statements](statements.md#array-handling-statements) 90 | * [Using statement](statements.md#using-statement) 91 | * [Await Statement](statements.md#await-statement) 92 | * [Yield Statement](statements.md#yield-statement) 93 | * [Expressions](expressions.md#expressions) 94 | * [Expression Classifications](expressions.md#expression-classifications) 95 | * [Constant Expressions](expressions.md#constant-expressions) 96 | * [Late-Bound Expressions](expressions.md#late-bound-expressions) 97 | * [Simple Expressions](expressions.md#simple-expressions) 98 | * [Type Expressions](expressions.md#type-expressions) 99 | * [Member Access Expressions](expressions.md#member-access-expressions) 100 | * [Dictionary Member Access Expressions](expressions.md#dictionary-member-access-expressions) 101 | * [Invocation Expressions](expressions.md#invocation-expressions) 102 | * [Overload Resolution](overload-resolution.md) 103 | * [Specificity of members/types given an argument list](overload-resolution.md#specificity-of-memberstypes-given-an-argument-list) 104 | * [Genericity](overload-resolution.md#genericity) 105 | * [Applicability to Argument List](overload-resolution.md#applicability-to-argument-list) 106 | * [Passing Arguments, and Picking Arguments for Optional Parameters](overload-resolution.md#passing-arguments-and-picking-arguments-for-optional-parameters) 107 | * [Conditional Methods](overload-resolution.md#conditional-methods) 108 | * [Type Argument Inference](overload-resolution.md#type-argument-inference) 109 | * [Index Expressions](expressions.md#index-expressions) 110 | * [New Expressions](expressions.md#new-expressions) 111 | * [Cast Expressions](expressions.md#cast-expressions) 112 | * [Operator Expressions](expressions.md#operator-expressions) 113 | * [Arithmetic Operators](expressions.md#arithmetic-operators) 114 | * [Relational Operators](expressions.md#relational-operators) 115 | * [Like Operator](expressions.md#like-operator) 116 | * [Concatenation Operator](expressions.md#concatenation-operator) 117 | * [Logical Operators](expressions.md#logical-operators) 118 | * [Shift Operators](expressions.md#shift-operators) 119 | * [Boolean Expressions](expressions.md#boolean-expressions) 120 | * [Lambda Expressions](expressions.md#lambda-expressions) 121 | * [Query Expressions](expressions.md#query-expressions) 122 | * [Conditional Expressions](expressions.md#conditional-expressions) 123 | * [XML Literal Expressions](expressions.md#xml-literal-expressions) 124 | * [XML Member Access Expressions](expressions.md#xml-member-access-expressions) 125 | * [Await Operator](expressions.md#await-operator) 126 | * [Documentation Comments](documentation-comments.md#documentation-comments) 127 | * [Documentation Comment Format](documentation-comments.md#documentation-comment-format) 128 | * [Recommended tags](documentation-comments.md#recommended-tags) 129 | * [ID Strings](documentation-comments.md#id-strings) 130 | * [Documentation comments example](documentation-comments.md#documentation-comments-example) 131 | * Grammar: [vb.html](http://ljw1004.github.io/vbspec/vb.html). Or download in ANTLR format: [vb.g4](http://ljw1004.github.io/vbspec/vb.g4?raw=true). 132 | 133 | 134 | *Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See [License.txt](https://github.com/dotnet/roslyn/blob/master/License.txt) for license information.* 135 | 136 | -------------------------------------------------------------------------------- /spec/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction to Visual Basic 2 | 3 | The Microsoft® Visual Basic® programming language is a high-level programming language for the Microsoft .NET Framework. Although it is designed to be an approachable and easy-to-learn language, it is also powerful enough to satisfy the needs of experienced programmers. The Visual Basic programming language has a syntax that is similar to English, which promotes the clarity and readability of Visual Basic code. Wherever possible, meaningful words or phrases are used instead of abbreviations, acronyms, or special characters. Extraneous or unneeded syntax is generally allowed but not required. 4 | 5 | The Visual Basic programming language can be either a strongly typed or a loosely typed language. Loose typing defers much of the burden of type checking until a program is already running. This includes not only type checking of conversions but also of method calls, meaning that the binding of a method call can be deferred until run-time. This is useful when building prototypes or other programs in which speed of development is more important than execution speed. The Visual Basic programming language also provides strongly typed semantics that performs all type checking at compile-time and disallows run-time binding of method calls. This guarantees maximum performance and helps ensure that type conversions are correct. This is useful when building production applications in which speed of execution and execution correctness is important. 6 | 7 | This document describes the Visual Basic language. It is meant to be a complete language description rather than a language tutorial or a user's reference manual. 8 | 9 | ## Grammar Notation 10 | 11 | This specification describes two grammars: a lexical grammar and a syntactic grammar. The lexical grammar defines how characters can be combined to form tokens; the syntactic grammar defines how the tokens can be combined to form Visual Basic programs. There are also several secondary grammars used for preprocessing operations like conditional compilation. 12 | 13 | The grammars in this specification are written in ANTLR format -- see http://www.antlr.org/. 14 | 15 | Case is unimportant in Visual Basic programs. For simplicity, all terminals will be given in standard casing, but any casing will match them. Terminals that are printable elements of the ASCII character set are represented by their corresponding ASCII characters. Visual Basic is also width insensitive when matching terminals, allowing full-width Unicode characters to match their half-width Unicode equivalents, but only on a whole-token basis. A token will not match if it contains mixed half-width and full-width characters. 16 | 17 | Line breaks and indentation may be added for readability and are not part of the production. 18 | 19 | ## Compatibility 20 | 21 | An important feature of a programming language is compatibility between different versions of the language. If a newer version of a language does not accept the same code as a previous version of the language, or interprets it differently than the previous version, then a burden can be placed on a programmer when upgrading his code from one version of the language to another. As such, compatibility between versions must be preserved except when the benefit to language consumers is of a clear and overwhelming nature. 22 | 23 | The following policy governs changes to the Visual Basic language between versions. The term language, when used in this context, refers only to the syntactic and semantic aspects of the Visual Basic language itself and does not include any .NET Framework classes included as a part of the `Microsoft.VisualBasic` namespace (and sub-namespaces). All classes in the .NET Framework are covered by a separate versioning and compatibility policy outside the scope of this document. 24 | 25 | ### Kinds of compatibility breaks 26 | 27 | In an ideal world, compatibility would be 100% between the existing version of Visual Basic and all future versions of Visual Basic. However, there may be situations where the need for a compatibility break may outweigh the cost it may impose on programmers. Such situations are: 28 | 29 | * *New warnings.* Introducing a new warning is not, per se, a compatibility break. However, because many developers compile with "treat warnings as errors" turned on, extra care must be taken when introducing warnings. 30 | 31 | * *New keywords.* Introducing new keywords may be necessary when introducing new language features. Reasonable efforts will be made to choose keywords that minimize the possibility of collision with users' identifiers and to use existing keywords where it makes sense. Help will be provided to upgrade projects from previous versions and escape any new keywords. 32 | 33 | * *Compiler bugs.* When the compiler's behavior is at odds with a documented behavior in the language specification, fixing the compiler behavior to match the documented behavior may be necessary. 34 | 35 | * *Specification bug.* When the compiler is consistent with the language specification but the language specification is clearly wrong, changing the language specification and the compiler behavior may be necessary. The phrase "clearly wrong" means that the documented behavior runs counter to what a clear and unambiguous majority of users would expect and produces highly undesirable behavior for users. 36 | 37 | * *Specification ambiguity.* When the language specification should spell out what happens in a particular situation but doesn't, and the compiler handles the situation in a way that is either inconsistent or clearly wrong (using the same definition from the previous point), clarifying the specification and correcting the compiler behavior may be necessary. In other words, when the specification covers cases a, b, d and e, but omits any mention of what happens in case c, and the compiler behaves incorrectly in case c, it may be necessary to document what happens in case c and change the behavior of the compiler to match. (Note that if the specification was ambiguous as to what happens in a situation and the compiler behaves in a manner that is not clearly wrong, the compiler behavior becomes the de facto specification.) 38 | 39 | * *Making run-time errors into compile-time errors.* In a situation where code is 100% guaranteed to fail at runtime (i.e. the user code has an unambiguous bug in it), it may be desirable to add a compile-time error that catches the situation. 40 | 41 | * *Specification omission.* When the language specification does not specifically allow or disallow a particular situation and the compiler handles the situation in a way that is undesirable (if the compiler behavior was clearly wrong, it would a specification bug, not a specification omission), it may be necessary to clarify the specification and change the compiler behavior. In addition to the usual impact analysis, changes of this kind are further restricted to cases where the impact of the change is considered to be extremely minimal and the benefit to developers is very high. 42 | 43 | * *New features.* In general, introducing new features should not change existing parts of the language specification or the existing behavior of the compiler. In the situation where introducing a new feature requires changing the existing language specification, such a compatibility break is reasonable only if the impact would be extremely minimal and the benefit of the feature is high. 44 | 45 | * *Security.* In extraordinary situations, security concerns may necessitate a compatibility break, such as removing or modifying a feature that is inherently insecure and poses a clear security risk for users. 46 | 47 | The following situations are not acceptable reasons for introducing compatibility breaks: 48 | 49 | * *Undesirable or regrettable behavior.* Language design or compiler behavior which is reasonable but considered undesirable or regrettable in retrospect is not a justification for breaking backward compatibility. The language deprecation process, covered below, must be used instead. 50 | 51 | * *Anything else.* Otherwise, compiler behavior remains backwards compatible. 52 | 53 | ### Impact Criteria 54 | 55 | When considering whether a compatibility break might be acceptable, several criteria are used to determine what the impact of the change might be. The greater the impact, the higher the bar for accepting the compatibility breaks. 56 | 57 | The criteria are: 58 | 59 | * What is the scope of the change? In other words, how many programs are likely to be affected? How many users are likely to be affected? How common will it be to write code that is affected by the change? 60 | 61 | * Do any workarounds exist to get the same behavior prior to the change? 62 | 63 | * How obvious is the change? Will users get immediate feedback that something has changed, or will their programs just execute differently? 64 | 65 | * Can the change be reasonably addressed during upgrade? Is it possible to write a tool that can find the situation in which the change occurs with perfect accuracy and change the code to work around the change? 66 | 67 | * What is the community feedback on the change? 68 | 69 | ### Language deprecation 70 | 71 | Over time, parts of the language or compiler may become deprecated. As discussed previously, it is not acceptable to break compatibility to remove such deprecated features. Instead, the following steps must be followed: 72 | 73 | 1. Given a feature that exists in version *A* of Visual Studio, feedback must be solicited from the user community on deprecation of the feature and full notice given before any final deprecation decision is made. The deprecation process may be reversed or abandoned at any point based on user community feedback. 74 | 75 | 2. full version (i.e. not a point release) *B* of Visual Studio must be released with compiler warnings that warn of deprecated usage. The warnings must be on by default and can be turned off. The deprecations must be clearly documented in the product documentation and on the web. 76 | 77 | 3. A full version *C* of Visual Studio must be released with compiler warnings that cannot be turned off. 78 | 79 | 4. A full version *D* of Visual Studio must subsequently be released with the deprecated compiler warnings converted into compiler errors. The release of *D* must occur after the end of the Mainstream Support Phase (5 years as of this writing) of release *A*. 80 | 81 | 5. Finally, a version *E* of Visual Studio may be released that removes the compiler errors. 82 | 83 | Changes that cannot be handled within this deprecation framework will not be allowed. 84 | -------------------------------------------------------------------------------- /spec/preprocessing-directives.md: -------------------------------------------------------------------------------- 1 | # Preprocessing Directives 2 | 3 | Once a file has been lexically analyzed, several kinds of source preprocessing occur. The most important, conditional compilation, determines which source is processed by the syntactic grammar; two other types of directives -- external source directives and region directives -- provide meta-information about the source but have no effect on compilation. 4 | 5 | ## Conditional Compilation 6 | 7 | Conditional compilation controls whether sequences of logical lines are translated into actual code. At the beginning of conditional compilation, all logical lines are enabled; however, enclosing lines in conditional compilation statements may selectively disable those lines within the file, causing them to be ignored during the rest of the compilation process. 8 | 9 | ```antlr 10 | CCStart 11 | : CCStatement* 12 | ; 13 | 14 | CCStatement 15 | : CCConstantDeclaration 16 | | CCIfGroup 17 | | LogicalLine 18 | ; 19 | 20 | CCExpression 21 | : LiteralExpression 22 | | CCParenthesizedExpression 23 | | CCSimpleNameExpression 24 | | CCCastExpression 25 | | CCOperatorExpression 26 | | CCConditionalExpression 27 | ; 28 | 29 | CCParenthesizedExpression 30 | : '(' CCExpression ')' 31 | ; 32 | 33 | CCSimpleNameExpression 34 | : Identifier 35 | ; 36 | 37 | CCCastExpression 38 | : 'DirectCast' '(' CCExpression ',' TypeName ')' 39 | | 'TryCast' '(' CCExpression ',' TypeName ')' 40 | | 'CType' '(' CCExpression ',' TypeName ')' 41 | | CastTarget '(' CCExpression ')' 42 | ; 43 | 44 | CCOperatorExpression 45 | : CCUnaryOperator CCExpression 46 | | CCExpression CCBinaryOperator CCExpression 47 | ; 48 | 49 | CCUnaryOperator 50 | : '+' | '-' | 'Not' 51 | ; 52 | 53 | CCBinaryOperator 54 | : '+' | '-' | '*' | '/' | '\\' | 'Mod' | '^' | '=' 55 | | '<' '>' | '<' | '>' | '<' '=' | '>' '=' | '&' 56 | | 'And' | 'Or' | 'Xor' | 'AndAlso' | 'OrElse' 57 | | '<' '<' | '>' '>' 58 | ; 59 | 60 | CCConditionalExpression 61 | : 'If' '(' CCExpression ',' CCExpression ',' CCExpression ')' 62 | | 'If' '(' CCExpression ',' CCExpression ')' 63 | ; 64 | ``` 65 | 66 | 67 | For example, the program 68 | 69 | ```vb 70 | #Const A = True 71 | #Const B = False 72 | 73 | Class C 74 | 75 | #If A Then 76 | Sub F() 77 | End Sub 78 | #Else 79 | Sub G() 80 | End Sub 81 | #End If 82 | 83 | #If B Then 84 | Sub H() 85 | End Sub 86 | #Else 87 | Sub I() 88 | End Sub 89 | #End If 90 | 91 | End Class 92 | ``` 93 | 94 | produces the exact same sequence of tokens as the program 95 | 96 | ```vb 97 | Class C 98 | Sub F() 99 | End Sub 100 | 101 | Sub I() 102 | End Sub 103 | End Class 104 | ``` 105 | 106 | The constant expressions allowed in conditional compilation directives are a subset of general constant expressions. 107 | 108 | The preprocessor allows whitespace and explicit line continuations before and after every token. 109 | 110 | 111 | ### Conditional Constant Directives 112 | 113 | Conditional constant statements define constants that exist in a separate conditional compilation declaration space scoped to the source file. 114 | 115 | ```antlr 116 | CCConstantDeclaration 117 | : '#' 'Const' Identifier '=' CCExpression LineTerminator 118 | ; 119 | ``` 120 | 121 | The declaration space is special in that no explicit declaration of conditional compilation constants is necessary -- conditional constants can be implicitly defined in a conditional compilation directive. 122 | 123 | Prior to being assigned a value, a conditional compilation constant has the value `Nothing`. When a conditional compilation constant is assigned a value, which must be a constant expression, the type of the constant becomes the type of the value being assigned to it. A conditional compilation constant may be redefined multiple times throughout a source file. 124 | 125 | For example, the following code prints only the string `about to print value` and the value of `Test`. 126 | 127 | ```vb 128 | Module M1 129 | Sub PrintValue(Test As Integer) 130 | 131 | #Const DebugCode = True 132 | 133 | #If DebugCode Then 134 | Console.WriteLine("about to print value") 135 | #End If 136 | 137 | #Const DebugCode = False 138 | 139 | Console.WriteLine(Test) 140 | 141 | #If DebugCode Then 142 | Console.WriteLine("printed value") 143 | #End If 144 | 145 | End Sub 146 | End Module 147 | ``` 148 | 149 | The compilation environment may also define conditional constants in a conditional compilation declaration space. 150 | 151 | 152 | ### Conditional Compilation Directives 153 | 154 | Conditional compilation directives control conditional compilation. 155 | 156 | ```antlr 157 | CCIfGroup 158 | : '#' 'If' CCExpression 'Then'? LineTerminator CCStatement* 159 | CCElseIfGroup* CCElseGroup? '#' 'End' 'If' LineTerminator 160 | ; 161 | 162 | CCElseIfGroup 163 | : '#' ElseIf CCExpression 'Then'? LineTerminator CCStatement* 164 | ; 165 | 166 | CCElseGroup 167 | : '#' 'Else' LineTerminator CCStatement* 168 | ; 169 | ``` 170 | 171 | Conditional constants can only reference constant expressions and conditional compilation constants. Each of the constant expressions within a single conditional compilation group is evaluated and converted to the `Boolean` type in textual order from first to last until one of the conditional expressions evaluates to `True`. If an expression is not convertible to `Boolean`, a compile-time error results. Permissive semantics and binary string comparisons are always used when evaluating conditional compilation constant expressions, regardless of any `Option` directives or compilation environment settings. 172 | 173 | All lines enclosed by the group, including nested conditional compilation directives, are disabled except for lines between the statement containing the `True` expression and the next conditional statement of the group, or lines between the `Else` statement and the `End If` statement if an `Else` appears in the group and all of the expressions evaluate to `False`. 174 | 175 | In this example, the call to `WriteToLog` in the `Trace` conditional compilation directive is not processed because the surrounding `Debug` conditional compilation directive evaluates to `False`. 176 | 177 | ```vb 178 | #Const Debug = False ' Debugging off 179 | #Const Trace = True ' Tracing on 180 | 181 | Class PurchaseTransaction 182 | Sub Commit() 183 | 184 | #If Debug Then 185 | CheckConsistency() 186 | #If Trace Then 187 | WriteToLog(Me.ToString()) 188 | #End If 189 | #End If 190 | ... 191 | End Sub 192 | End Class 193 | ``` 194 | 195 | 196 | ## External Source Directives 197 | 198 | A source file may include external source directives that indicate a mapping between source lines and text external to the source. 199 | 200 | ```antlr 201 | ESDStart 202 | : ExternalSourceStatement* 203 | ; 204 | 205 | ExternalSourceStatement 206 | : ExternalSourceGroup 207 | | LogicalLine 208 | ; 209 | 210 | ExternalSourceGroup 211 | : '#' 'ExternalSource' '(' StringLiteral ',' IntLiteral ')' LineTerminator 212 | LogicalLine* '#' 'End' 'ExternalSource' LineTerminator 213 | ; 214 | ``` 215 | 216 | External source directives have no effect on compilation and may not be nested. For example: 217 | 218 | ```vb 219 | Module Test 220 | Sub Main() 221 | 222 | #ExternalSource("c:\wwwroot\inetpub\test.aspx", 30) 223 | Console.WriteLine("In test.aspx") 224 | #End ExternalSource 225 | 226 | End Sub 227 | End Module 228 | ``` 229 | 230 | 231 | ## Region Directives 232 | 233 | Region directives group lines of source code but have no other effect on compilation. The entire group can be collapsed and hidden, or expanded and viewed, in the integrated development environment (IDE). 234 | 235 | ```antlr 236 | RegionStart 237 | : RegionStatement* 238 | ; 239 | 240 | RegionStatement 241 | : RegionGroup 242 | | LogicalLine 243 | ; 244 | 245 | RegionGroup 246 | : '#' 'Region' StringLiteral LineTerminator 247 | RegionStatement* 248 | '#' 'End' 'Region' LineTerminator 249 | ; 250 | ``` 251 | 252 | Regions may be nested. Region directives are special in that they can neither start nor terminate within a method body, and they must respect the block structure of the program. For example: 253 | 254 | ```vb 255 | Module Test 256 | #Region "Startup code - do not edit" 257 | Sub Main() 258 | End Sub 259 | #End Region 260 | 261 | End Module 262 | 263 | 264 | ' Error due to Region directives breaking the block structure 265 | Class C 266 | #Region "Fred" 267 | End Class 268 | #End Region 269 | ``` 270 | 271 | 272 | ## External Checksum Directives 273 | 274 | A source file may include an external checksum directive that indicates what checksum should be emitted for a file referenced in an external source directive. In all other respects external source directives have no effect on compilation. 275 | 276 | ```antlr 277 | ExternalChecksumStart 278 | : ExternalChecksumStatement* 279 | ; 280 | 281 | ExternalChecksumStatement 282 | : '#' 'ExternalChecksum' '(' 283 | StringLiteral ',' StringLiteral ',' StringLiteral 284 | ')' LineTerminator 285 | ; 286 | ``` 287 | 288 | An external checksum directive contains the filename of the external file, a globally unique identifier (GUID) associated with the file and the checksum for the file. The GUID is specified as a string constant of the form "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}", where x is a hexadecimal digit. The checksum is specified as a string constant of the form "xxxx...", where x is a hexadecimal digit. The number of digits in a checksum must be an even number. 289 | 290 | An external file may have multiple external checksum directives associated with it provided that all of the GUID and checksum values match exactly. If the name of the external file matches the name of a file being compiled, the checksum is ignored in favor of the compiler's checksum calculation. 291 | 292 | For example: 293 | 294 | ```vb 295 | #ExternalChecksum("c:\wwwroot\inetpub\test.aspx", _ 296 | "{12345678-1234-1234-1234-123456789abc}", _ 297 | "1a2b3c4e5f617239a49b9a9c0391849d34950f923fab9484") 298 | 299 | Module Test 300 | Sub Main() 301 | 302 | #ExternalSource("c:\wwwroot\inetpub\test.aspx", 30) 303 | Console.WriteLine("In test.aspx") 304 | #End ExternalSource 305 | 306 | End Sub 307 | End Module 308 | ``` 309 | 310 | --------------------------------------------------------------------------------