|
| 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: <HideModuleName> |
| 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#: [<RequiresQualification>] |
| 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 <HideModuleName>? |
| 76 | +A. Intellisense will ignore this attribute on strict modules. |
| 77 | + |
| 78 | + |
| 79 | + |
| 80 | +--- |
| 81 | + |
| 82 | +On Apr 15, 2014 at 2:45 AM @BillMcC wrote: |
| 83 | + |
| 84 | +Like the concept, don't like the name. "Strict Module" in VB implies to me the code inside this module is Option Strict On// strictly speaking that is ;) |
| 85 | + |
| 86 | +"Shared Class" on the other hand is what I would expect when translating "static class" from C#. It would also fit closest to the case of partial private sub new scenario. |
| 87 | + |
| 88 | +It would also be nice if we could turn OFF all auto importing. For example, let's say Console is a standard module and gets auto-opened. In a VB project with |
| 89 | +Imports Microsoft.VisualBasic |
| 90 | +Imports System |
| 91 | + |
| 92 | +You'd be faced with conflict resolution over Writeline. |
| 93 | + |
| 94 | +It'd be nice to be able to indicate you don't want unqualified access to shared class members. (aliases is too narrow/ugly) |
| 95 | +For VB, this would have to be surfaced as an "Option", eg Option AutoImports Off or something like that. |
| 96 | + |
| 97 | +--- |
| 98 | + |
| 99 | +On Apr 15, 2014 at 12:26 PM @KathleenDollard wrote: |
| 100 | + |
| 101 | +Did you mean "Shared Class" (then I'll reread because I didn't get it) |
| 102 | +or |
| 103 | +Did you typo and mean "Shared Module"? |
| 104 | + |
| 105 | +--- |
| 106 | + |
| 107 | +On Apr 15, 2014 at 1:08 PM @BillMcC wrote: |
| 108 | + |
| 109 | +Shared Class. A Module is already Shared//static |
| 110 | + |
| 111 | +--- |
| 112 | + |
| 113 | +On Apr 17, 2014 at 5:06 AM @lonewolfcj wrote: |
| 114 | + |
| 115 | +Definitely agree that the Partial Private Sub workaround should be retired (creativity notwithstanding)! |
| 116 | + |
| 117 | +I like BillMcC's Shared Class suggestion. My only question about it is based on how I've used Modules and Classes...I'll use a module when each declaration stands on its own and I don't want a constructor (even though I can add a constructor to a Module I never do - I would create a Shared Sub New in a class instead). |
| 118 | + |
| 119 | + |
| 120 | +#PROPOSAL: USE "CONTAINED MODULE" |
| 121 | + |
| 122 | +So, for the scenario in which I want to add to a namespace but do not want the declarations lifted, I prefer something like "Contained Module" to "Strict Module." I think that using the Strict keyword conflates with the existing definition of Strict and doesn't cleanly describe what it's actually being Strict about. Conversely, "Contained" I think describes the intent more clearly - that the members are only accessible if you specify the containing module's name. |
| 123 | + |
| 124 | +``` |
| 125 | +Contained Module Monkey 'basically a namespace container (scaffolding a level of the hierarchy) |
| 126 | + Public Function x() as Integer = Year(Now) 'shameless plug for expression as return value |
| 127 | +End Module |
| 128 | +
|
| 129 | +Module PervasiveMonkey 'lifted for general use |
| 130 | + Public Function y() as Integer |
| 131 | + Return 20 |
| 132 | + End Function |
| 133 | +End Module |
| 134 | +
|
| 135 | +Module Program |
| 136 | + Public Sub New() |
| 137 | + Console.Writeline(Monkey.x) |
| 138 | + Console.Writeline(y) |
| 139 | + End Sub |
| 140 | +End Module |
| 141 | +``` |
| 142 | + |
| 143 | +#IDEA: IMPLICITLY CREATE CONTAINED MODULES |
| 144 | +_(This one might be boutique exotic goldplating heresy)_...to add to the Contained Module concept - another idea would be to allow adding declarations directly into a Namespace block and let VB create implicit Contained Modules (c# static classes) from the outermost namespace level. |
| 145 | + |
| 146 | +so: |
| 147 | + |
| 148 | +``` |
| 149 | +Namespace Grover.Cleveland |
| 150 | + Function AmIPresidential() as Boolean = True |
| 151 | +End Namespace |
| 152 | +``` |
| 153 | + |
| 154 | +Would create an implicit Contained Module Cleveland (static class) in the Grover namespace, as: |
| 155 | + |
| 156 | +``` |
| 157 | +.namespace Grover |
| 158 | +{ |
| 159 | + .class private abstract auto ansi sealed beforefieldinit Cleveland |
| 160 | + { |
| 161 | + .method public static boolean AmIPresidential() cil managed |
| 162 | + { |
| 163 | + ... |
| 164 | + } |
| 165 | + } |
| 166 | +} |
| 167 | +``` |
| 168 | + |
| 169 | +_(Adding a Cleveland Class in the Grover Namespace would be met with an error since it's already implicitly defined as a Contained Module)._ |
| 170 | + |
| 171 | +#PROPOSAL: ALLOW NESTING OF CONTAINED MODULES |
| 172 | + |
| 173 | +Contained Modules (whether explicitly or implicitly defined) could accommodate nesting, which would be useful when laying out static hierarchies. The current alternative is to either create explicit Namespace blocks or rely on nesting Public Classes within Modules and play tricks to eliminate the constructors (which won't even be an option anymore). |
| 174 | + |
| 175 | +``` |
| 176 | +Contained Module RootModule |
| 177 | + Function Here() as String = "Quip" |
| 178 | +
|
| 179 | + Contained Module NestedModule ' |
| 180 | + Function InHere() as String = "Quill Pen" |
| 181 | + End Module |
| 182 | +End Module |
| 183 | +``` |
| 184 | + |
| 185 | +_(Regular Modules cannot be nested within a Contained Module)_ |
| 186 | + |
| 187 | +``` |
| 188 | +Module Program |
| 189 | + Sub Main() |
| 190 | + Console.Writeline(RootModule.Here) |
| 191 | + Console.Writeline(RootModule.NestedModule.InHere) |
| 192 | +
|
| 193 | + 'also, accessing a static from a With Block would be highly convenient: |
| 194 | + With RootModule |
| 195 | + Console.Writeline(.NestedModule.InHere) |
| 196 | + End With |
| 197 | + End Sub |
| 198 | +End Module |
| 199 | +``` |
| 200 | + |
| 201 | + |
| 202 | +--- |
| 203 | + |
| 204 | +On Sep 19, 2014 at 10:44 PM @lonewolfcj wrote: |
| 205 | + |
| 206 | +Lucian/Anthony, |
| 207 | + |
| 208 | +I read the 9/10 updates to the comment and am still perplexed as to why Explicit Modules could not be nested? This would be useful, particularly when organizing hierarchies of shared methods. Nesting classes with shared methods works fine but I think a key distinction between modules and classes are that modules cannot be instantiated. So it would then be useful to have nested modules as the better option for that use case. |
| 209 | + |
| 210 | +Craig. |
| 211 | + |
| 212 | +--- |
| 213 | + |
| 214 | +On Sep 20, 2014 at 11:10 PM @ADGreen wrote: |
| 215 | + |
| 216 | +Hey Craig, |
| 217 | + |
| 218 | +I'm not sure to which update you refer but the general feeling in the VB LDM was that nesting should be permitted for the reasons you mention. In general the momentum was behind complete functional parity with C#'s static classes, so: |
| 219 | +* Nesting should be permitted. |
| 220 | +* Being generic should be permitted. |
| 221 | +* Being partial should be permitted. |
| 222 | + |
| 223 | +All of those capabilities needn't be implemented at the same time though. The highest priority scenario identified was not spilling their members into the containing namespace. |
| 224 | + |
| 225 | +__-ADG__ |
| 226 | + |
| 227 | +--- |
| 228 | + |
| 229 | +On Sep 21, 2014 at 4:03 PM @lonewolfcj wrote: |
| 230 | + |
| 231 | +Anthony, |
| 232 | + |
| 233 | +Good to hear. I was referring to the original post which was updated on 9/10 with (what I thought was) your suggestion to create "Explicit Module". I matched that to the Semantics section which says: |
| 234 | + |
| 235 | +"Q. Nesting? Currently VB modules can't be nested. C# static classes can be nested. |
| 236 | +RESOLUTION: Strict modules cannot be nested." |
| 237 | + |
| 238 | +So I drew the conclusion that the first cut of Explicit Modules will not allow nesting. |
| 239 | + |
| 240 | +Craig. |
| 241 | + |
| 242 | + |
| 243 | +--- |
| 244 | + |
0 commit comments