Open bclothier opened 2 years ago
@WaynePhillipsEA
Public/Private at this level will simply denote whether the alias gets exported to the type library, or not.
the current situation for Public Class vs Private Class, which also denotes whether the class will be exposed via the generated type library
IMO that is a waste of Public/Private modifiers, that's an Exported/Not Exported thing (maybe an attribute or new keyword could be used or Exposed
). Public/Private on variables restricts scope to that component, Public/Private on components (class/module) should I think restrict access to the file (.twin). .bas and .cls files would be implicitly Public Module/ Public Class
for bwds compatibility.
Typedefs could be treated as another kind of component like a module or a class I agree, in terms of scope.
Public/Private keywords are so fundamental and important we should use them more carefully. They are a fantastic resource for leveraging people's existing understanding and expectations from VBA to learn a new tB concept. Making dll libraries is only one of the many things you can do with tB (make an exe, a CLI app, a GUI app, a device driver), why should the access modifiers only be useful for that usecase and not the language as a whole? I may make a separate discussion about this.
Originally posted by @Greedquest in https://github.com/twinbasic/lang-design/issues/32#issuecomment-1219620279
I don't think there's a need, in a full application as opposed to TLB/OCX, to impose an artificial restriction on usage, and there should be strong support for using it in all project types, as opposed to primarily for ActiveX controls.
I'd propose having Public Alias/Private Alias within the regular code, behave exactly as those keywords apply to Public/Private type, but Public Alias wouldn't be exported by default, you could tag it with [ COMExport ] instead of Dll to export it.
This would replicate the typedef vs typedef [public] distinction in TLBs, and provide consistent functionality in all project types.
Originally posted by @fafalone in https://github.com/twinbasic/lang-design/issues/32#issuecomment-1219627883
@Greedquest I would welcome a discussion about that. I think perhaps changing it to Class
and Internal Class
or similar might be more clear and less ambiguous. Same for Alias
and Internal Alias
, perhaps.
Originally posted by @WaynePhillipsEA in https://github.com/twinbasic/lang-design/issues/32#issuecomment-1219627914
I'd propose having Public Alias/Private Alias within the regular code, behave exactly as those keywords apply to Public/Private type, but Public Alias wouldn't be exported by default, you could tag it with [ COMExport ] instead of Dll to export it.
One concern I see with that approach is that in tB, we can MyProject.Export.FizzBuzz
but in COM-consuming code, it'd be illegal syntax. It'd be just MyProject.FizzBuzz
. Wouldn't that lead to confusion in code usage in both contexts?
Originally posted by @bclothier in https://github.com/twinbasic/lang-design/issues/32#issuecomment-1219640062
Component only scope need not be implemented right away, but the syntax should be designed with the eventual implementation in mind; it could just generate an error for now like when Public is used where it can't be.
@blothier, can you clarify what you mean? I'm not familiar with a .Export method.
Originally posted by @fafalone in https://github.com/twinbasic/lang-design/issues/32#issuecomment-1219647694
@fafalone,
can you clarify what you mean? I'm not familiar with a .Export method.
It's the name of the hypothetical module. As mentioned, type hierarchy isn't supported in the COM context, so though it's legal for tB or VBx to fully qualify <project>.<component>.<member>
, the same syntax wouldn't work outside that context which also can include VBx code that has the library referenced and thus only see what COM sees. It'd have to be <project>.<member>
.
Originally posted by @bclothier in https://github.com/twinbasic/lang-design/issues/32#issuecomment-1219653714
I wouldn't think my hypothetical [ COMExport ] could be used on Private Alias. Private would always be Private only to that module/class/form/etc.
Besides that; how is this handled with Type and Enum? I guess I'm confused about how it's being treated different than that.
Originally posted by @fafalone in https://github.com/twinbasic/lang-design/issues/32#issuecomment-1219662064
Why not just cut through the potential confusion from the start? Change the public/Private keyword prefixes to be directly applicable to the COM or DLL contexts to which they apply.
So: for COM components: COMPublic Type xxx...
for DLL: DLLPublic Type xxx....
That way the context of the type declaration is crystal clear to future devs looking at the code in intellisense, then the (DLL) or (COM) can easily be shown as well.
I'm all for anything worthwhile that reduces confusion in reading/comprehending code, and making the meaning of Public or Private any more confusing than they can be already now would not be a Good Thing(TM).
Originally posted by @mburns08109 in https://github.com/twinbasic/lang-design/issues/32#issuecomment-1219693521
Let me clarify the above suggestion a tad (since Ben moved my comment and I can't edit it anymore now).
So, For COM components (and IDL): COMPublic Type xxx... (or) COMPublic Alias xxx... (whichever direction we go in)
The point here is to NOT muddy the water of what Public/Private/Friend (or any other potential scope modifiers you care to throw into this list, Static or Isolated, perhaps?) mean in all other instances with any potential additional confusion about whether we're caring more about DLL-scope-related TYPE/Alias definitions or COM/IDL-scope-related TYPE/Alias definitions.
Call them out for what we need to be clear about from the beginning with a new scope label that clearly says what it means.
Public and COMPublic seems confusing... Maybe Export Alias? COMExport? But wouldn't that be de facto the same as a more consistent [ COMExport ] like we have [ DllExport ]?
All clarify it's not the same as Public Type and Private Type.
Doh. After moving the thread, I now realize there already was a thread about that. However, it started out specific to Module
. Still, we should discuss the question about public/private in more general terms. For the record, I DO think this looks weird:
Private Module Foo
Public Sub Bar()
End Sub
End Module
Given that the Module
and Class
statements are new to tB, I would have preferred to use only either Public
or Internal
for those top-level components as that's less confusing.
In regards to the COM/DLL exports.... I will have to pull out my old soapbox and re-state the case against making it a language syntax.
I've commented about the need to keep clean separation between different concerns and I think type library generation does not belong as a language syntax but rather as an attribute. See here, here and here.
Stuff like DLL exports and type library generation are not language features. They are compiler services. Therefore creating a language syntax for them is a mistake. The language itself should be very small and should be abstract enough to work on any hardware. The type library generation and DLL exports are best described with attributes. I understand this isn't a perfect and clean separation because we already have language syntax that influences the corresponding services.
What does that mean? Simply that we don't add any new meaning to Public
/ Private
beyond what it already has. Because aliases (and we will have to deal with other elements such as unions as well) are something new to tB we have the freedom of defining it in the way that feels most natural.
Therefore, I'd argue that this is more natural extension:
Public Module Foo
[ LibraryExport ]
Public Alias Fizz As Long
End Module
This allow us to provide type-hierarchy for tB consumers (e.g. MyProject.Foo.Fizz
is a legal syntax among tB consumers) while having the ability to support COM consumers, which would be MyProject.Fizz
only.
The attribute can be used to perform validation that there is only one alias Fizz
defined in the MyProject
and throw an error about duplicate definition if there's two aliases named Fizz
, even though they are in 2 different modules and thus legal/disambiguable.
There are 2 important points I think about language design:
Private
/Public
/Friend
are really important language keywords, which already carry connotations of modifying scope or access throughout the project. At the moment they are being wasted for a relatively niche purpose of typelib exposure and I agree with @bclothier, that job could be done with an attribute as it is more of a compiler feature anyway.
Option Private Module
and the class instancing settings, but the Option Private Module seems to have patchy support, and the instancing arguments I see as a subset of Public/Private, especially because in VBA you can't even New up a class in a referenced project. They need revisiting for tB basically. I know VB6 had a few more options here though..twin
files containing Module/Class statements bring a new superset level of structure over what was possible in VBx (because VBx had an entirely flat project structure). At the moment twin files are being wasted, it is basically arbitrary whether I declare a Module in fileA.twin or fileB.twin. They act very similarly to RD Folder annotations in grouping things visually but not affecting the code.
.bas
, .cls
etc. files to match existing VBx project structures, so .twin
files can and should be leveraged for an additional level of structure. It should mean something to the code for me to decide to put a module in one file or another..twin
files (and the virtual filesystem they live in) are not, and therefore could be much more powerful.tl;dr
That's the main point I wanted to get across, that there are 2 bad things about the current state of the language (or let's just say wasted opportunities where we can improve): 1) Private/Public/Friend
on components is only important for 1 usecase rather than the entire language, and 2) .twin
files are basically just RubberDuck @Folder
annotations when they could be used for so much more.
You can stop reading here if you like.
So yes my solution for both of these wasted opportunities is to use the access modifiers on components to dictate whether they go into the project scope or not, and are accessible from other files. I.e. right now we have:
Option Private
modules and Instancing: 1 - Private
classes, Friend
class methods, globally scope members of referenced dlls/addins. Accessible to callers inside the same project.Public Methods/Types
in components, and Public Instancing Classes + their Public Methods. Accessible to callers inside the project and exposed to the outside world when the project is referenced - PS this is confusing I feel.And we should change to have:
Private Module/Class
blocks. Accessible only to callers within the same file.Public Module/Class
blocks with no explicit exported
/dll visible
property, or .cls files with Instancing: Private
, or .bas files with option privatePublic Module/Class
blocks with an explicit exported
property, or Instancing: Public
.cls files, or .bas files.Now exposure to the outside world is explicit and optional. Much better structure. After all, I may have a file.twin that does something, but half the code in it is implementation details. That stuff should be encapsulated within the file and not leaked to the whole project (or worse, outside it). It should be a conscious decision to make components part of a file's public interface, just as we decide when to make methods part of a component's public interface.
Alternatively to be really VBx about it, Private
componets get File Scope, Friend
components get project scope, Public
components get Global scope and are visible from the typelib or tB projects which reference this one. That's less explicit which is bad but maybe more expected which is good.
v1 blocker, depending on outcome
The proposal to have Private Class ... End Class
or Friend Class ... End Class
would break existing tB behaviour so must be decided before v1 fixes the behaviour to what it is now
Sorry, wrong thread, deleted.
Indeed, my thoughts on this are based on COM type-library support, which doesn't offer type-hierarchy support. For example, UDTs are never parented by a coclass or module, only the library itself, unlike
Type
s defined in VBx. FWIW, I would also like to see us be able to optionally define UDTs at the same global scope, so that we can offer a more aligned approach to COM.So technically speaking, defining aliases at the global scope, along with Modules and Classes is more correct, from a COM perspective. The
Public
/Private
suggestion is an expansion of the current situation forPublic Class
vsPrivate Class
, which also denotes whether the class will be exposed via the generated type library.[DllExport]
has very specific meaning in my eyes, as it currently exactly relates to the exporting of DLL function entry points, and so to use it for this purpose would not be ideal IMO.Originally posted by @WaynePhillipsEA in https://github.com/twinbasic/lang-design/issues/32#issuecomment-1219618470