Closed medvednikov closed 5 years ago
Perhaps formatting should be different:
struct Foo {
private_field int
len -int
public_field +int
}
most readable for me
struct Foo {
private_field int
-len int
+public_field int
}
Yes, perhaps.
Functions:
fn +foo()
fn foo+()
same with functions when there are dozens or hundreds of them with names of various lengths, it will be difficult for you to look for postfixes. Should be prefixed, Immediately visible.
most readable for me
struct Foo { private_field int -len int +public_field int }
I agree with @whoizit suggestion. more readable for me, since it should be clear that access modifier is related to field name, not to field type.
Good point, let's do it this way.
why not using keywords?
why not using keywords?
I like the approach of Go and Oberon to achieve this without keywords.
Adding more keywords increases complexity of the language, and the definitions would look a lot more verbose:
struct Foo {
private_field int
readonly len int
public public_field int
}
oh, that makes sense
It would be also handy to allow minus as word separator in names. It is more readable than underscore.
-len
would mean read only
some-name
would be one symbol
-3
would be negative number
x - y
would be expression, spaces around the minus required
Yes, that would be nice, and I had precisely the same idea. Unfortunately it's not possible.
I don't want to make a whitespace sensitive language, and I want it to be similar to C/C++ and Go. This would be too big of a change for all these developers.
All these languages suffer of TooLongNamesDisease
. Especially C is asking for it. Since it looks that V won't allow function overloading, the pressure would be here too.
Words separated by dash are bit more readable than with underscore. (I noticed this in Lisp code.) Traditional typography employs en dash (Austria-Hungary
), underscore is a hack from age of typewriters.
If arithmetic operators always require spaces around, then it won't be confusing for the reader. There's low chance of accidentally joining two words and making valid symbol, which then even compiles.
Since it looks that V won't allow function overloading
I assumed that, but I would like V to allow overloading only on number of arguments. This is a lot simpler than C++ overloading, no complications about fn f(int)
vs fn f(i8)
etc.
Adding more keywords increases complexity of the language, and the definitions would look a lot more verbose
If we're using symbols for this, I think the same syntax for public and private should apply to functions and types. The default could be public, which for fields means read-only [outside the struct module] (to follow your design). Then -identifier
makes a symbol private. The special case would be +field
, which means read/write public field:
fn public_func(){}
fn -private_func(){}
struct -private_type{}
struct public_type {
read_only_public_field T
-private_field T
+read_write_public_field T
}
Immutable struct fields by default got a lot of support:
struct Foo {
foo1 int // can only be accessed in the same module, but not modified (default)
foo2 mut int // can only be accessed and modified in the same module
+foo3 int // read-only field that can be accessed from an outside module, but not modified
+foo4 mut int // public field that can be accessed and modified from an outside module
}
Immutable struct fields by default got a lot of support:
Yes, where I wrote T
, you can write e.g. mut int
. My comment here is about access only, mutability is a separate concern. In your reply it seems there's no way to have a field be mutable in the current module, but read-only outside it. Read-only public fields seems a good default for fields that are mutable in private. Also, what about functions and type access as I mentioned?
In your reply it seems there's no way to have a field be mutable in the current module, but read-only outside it.
Good point, this is the 5th option, and it's not handled.
So perhaps Oberon's readonly -
can be brought back for this:
struct Foo {
foo1 int // can only be accessed in the same module, but not modified (default)
foo2 mut int // can only be accessed and modified in the same module
+foo3 int // read-only field that can be accessed from an outside module, but not modified
+foo4 mut int // public field that can be accessed and modified from an outside module
-foo4 int // read-only field that can be accessed from an outside module and modified from an inside module
}
This is getting a bit complicated...
The default could be public
The default is private in all major languages, it's not going to change. The default must always be private.
I assumed that, but I would like V to allow overloading only on number of arguments.
There will never be function overloading:
There will never be function overloading
It is straying off topic, but:
There are valid reasons why function overloading got a really bad name:
If these mistakes are avoided, function overloading wouldn't be seen as a monster.
There are natural uses of overloading - math functions like sin/cos/etc. Even C realized it and attempted to add it into the language with C11. Unfortunately, they had chosen _Generic
.
Function name overloading has one not so obvious advantage - it reduces the pressure to use unreadable LongNamesWhichAreFiresureUnique
.
One also could take inspiration in Smalltalk, and use function parameter names as part of name resolution.
fn coordinates( x, y) // handles cartesian coordinates
fn coordinates(angle, len) // handles polar coordinates
result = coordinates(x: 10, y:20); // it is absolutely clear which overload is wanted here
The default must always be private.
OK.
-foo4 int // read-only field that can be accessed from an outside module and modified from an inside module
Read-only field syntax without mutable data should be an error, it's correct if mut int
is the field type. I don't think your example is that complicated, when thinking of mutability and private/public as two separate concepts.
But should functions and type names be public or private by default? If private then +identifier
would be a consistent way to make them public. If public, I don't think we can have -private_function_name
as well as -read_only_public_field
, it would be confusing.
The plus and minus look like operators.
I find this extremely confusing and noisy - the meaning of plus and minus aren't naturally understood as anything other than operators, so this is a bit too creative for my taste.
Fewer characters do not necessarily make something easier to parse for a person.
We're used to words like "public", "private", "internal" etc. from english language - and if not from there, then from other programming languages.
It seems like you're struggling to make everything as few characters as possible?
I think that's misguided.
In my opinion, readability of code is much more important than how many characters you have to type - simply having having characters does not automatically make a syntax more readable. Think regular expressions. Most people needs weeks to months to learn the basics. Whereas most people learn to read languages like Java (while it does tend to be overly verbose) almost immediately - even if they don't learn the meaning of the keywords, anyone can immediately identify the keywords, which gives them at least a way to automatically associate terminology with keywords, so they can ask questions, do a search or talk to more senior coworkers about them.
Compounding everything down to symbols (worse, ambiguous symbols) increases the density of the code, which isn't automatically a good thing. Keywords aren't just noise - when used properly, they reduce the density and add to the semantics of the language.
Be careful not to compress the syntax to the point of obfuscating.
I think the concerns of @mindplay-dk are valid and need to be considered. Though I personally actually prefer a symbol based system as it reduces the verbosity by a quite large amount compared to "private, internal, public" keywords. I also think it's important to remember that whereas fewer numbers of character doesn't, on its own, make for more readable syntax the opposite is also true. Otherwise we'd all be coding in COBOL-like languages.
I suspect that it's quite hard to know for sure which syntax would be more intuitive. While I get the idea of the regex comparison I don't think it's a very good comparison in this case. I'd personally like to argue that if you're a beginner it's not very clear what you can do to a "protected internal" property in C#. You need to know more than the dictionary definition of the actual words. And therefore I'm really not convinced that it's much harder to instead learn the contextual meaning of two or three different symbols. But that's just my personal thoughts, not backed by any reliable sources at all.
Though I personally actually prefer a symbol based system as it reduces the verbosity by a quite large amount compared to "private, internal, public" keywords.
I agree, it does reduce verbosity.
But it does so at the expense of readability due to increased visual ambiguity - words are unambiguously recognized by the majority of the population, possibly with the exception of dyslexics; most of whom do learn to read today, and/or can memorize the spelling of a few keywords. Even non-english speakers who know the latin alphabet learn to read and write keywords.
Learning the meaning of arbitrary symbols is harder - especially when those symbols are ambiguous.
Being able to visually scan and read code is extremely important.
While verbosity is of course also a concern, you shouldn't barrel down on that problem, or any single problem, at the expense of everything else. Good language design is about balancing trade-offs. Are you sure that's what you're doing here?
It seems to me like you're asking a lot of new users - be careful not to compress and obfuscate the syntax to the point that too many will just look at this and dismiss it outright. Most newcomers will already know another language, and will recognize common keywords with a common meaning from most other mainstream languages.
I'm all for trying new things, but in my opinion you're trying to innovate something that doesn't really need innovation, and making some detrimental trade-offs in the process.
struct Foo { private_field int -len int +public_field int }
sorry, are you seriously!!? what the 'hell' syntax?
The plus and minus look like operators.
Agree with this, but i'm not the big fan of keywords too, cause it's more verbosity. I wonder why nobody to recommend the design of Golang, capitalize the first letter or not.
I agree about the problematic ambiguity that comes with using the proposed + and -. I also think that the proposed meaning of the minus sign is far from obvious. But I think it'll probably be hard to come up with other symbol based modifiers that will be better and more intuitive. Though I still think that using "public" and "private" keywords does not feel like a good fit with the general syntax of V. Then I agree with @han2015 that it's worth considering Go's naming convention, considering that V is already sharing many similarities with Go.
I wonder why nobody to recommend the design of Golang, capitalize the first letter or not
In generic code it's very helpful to have type names Capitalized and variables starting lowercase. Otherwise it takes longer to work out what's going on in the code. For this reason I don't want to see Capitalized function names. If we want to change the symbol identifier itself to signify access, I'd prefer _symbol
to mean private. But using the identifier has an annoyance: having to update all uses of a private symbol when it's made public. That's straightforward with a good editor, but it also creates diff noise (possibly creating conflicts in another pull request, which can be more annoying).
I don't think traditional attributes are necessarily verbose: e.g. pub:
applying to all following fields until overridden. priv
can then override single fields, and vice versa.
fn +foo()
I missed this comment before, so with this syntax functions are private by default. With pub
/priv
it would be possible to have functions and types public by default, as well as fields private by default. That seems more like what is typically wanted in a module.
If the concern is sheer verbosity, a few languages opt for sectioning instead of annotations - for example:
struct User {
private {
id int
}
private mutable {
email string
}
public mutable {
first_name string
last_name string
}
}
This is visually unambiguous, and non-repetitive when you have to list 10-20 public or private fields.
Yes, this is an option. If we use C++ syntax and skip private
since all fields are private by default, we get
struct User {
id int
mutable:
email string
public mutable:
first_name string
last_name string
}
it would be possible to have functions and types public by default, as well as fields private by default. That seems more like what is typically wanted in a module.
Everything is going to be private by default. It's simpler, and that's how it works in all other languages.
@medvednikov that looks really nice and functional 👍
Yes, I like it too, and I even prefer the full names public
and mutable
here :)
mut
indeed is a very ugly word. F# uses let mutable x = 1
, maybe I should also replace mut x := 1
with mutable x := 1
.
Most variables shouldn't be mutable anyway.
Mutable version being more verbose might encourage people to make their variables immutable where possible.
Yes, this is an option. If we use C++ syntax and skip
private
since all fields are private by default, we getstruct User { id int mutable: email string public mutable: first_name string last_name string }
it would be possible to have functions and types public by default, as well as fields private by default. That seems more like what is typically wanted in a module.
Everything is going to be private by default. It's simpler, and that's how it works in all other languages.
Idk, but i didn't like this approach. too much things to typing with keyboard XD
@arhen this version is not going to be a lot more verbose when you have many fields:
struct User {
id int
mutable:
email string
public mutable:
first_name string
last_name string
field1, field2, field3, field4 string
}
struct User {
id int
email mut string
+first_name mut string
+last_name mut string
+field1 mut string
+field2 mut string
+field3 mut string
+field4 mut string
}
Just my 2 cents, how about using _
prepended to a name for delineating whether or not something is private?
struct User {
_private int
public int
}
fn _private() {
}
The sectioning example with private by default is by far my favourite this far, feels more clean and convenient than most other alternatives.
if we reduce function to fn, then we should reduce and public to pub and mutable to mut. But then it will be Rust) I personally like fn, pub, mut; private and immutable by default. wordiness is enough in other languages, It should be compact.
Yeah, I agree with this in the end.
struct User {
id int
mut:
email string
pub mut:
first_name string
last_name string
field1, field2, field3, field4 string
}
Just my 2 cents, how about using _ prepended to a name for delineating whether or not something is private?
This makes everything public by default, which is undesirable.
Also the majority of the module's code now has method calls starting with _
.
Yeah, I agree with this in the end.
struct User { id int mut: email string pub mut: first_name string last_name string field1, field2, field3, field4 string }
I like it.
mut indeed is a very ugly word. F# uses let mutable x = 1, maybe I should also replace mut x := 1 with mutable x := 1.
@medvednikov why did you go back on this in your last examples?
Please use proper words. pub mut
is so much less readable than public mutable
.
@mindplay-dk if it is a public mutable
, you should write function
instead of fn
. But then I will personally teach Rust, instead vlang.
Maybe if you want to write "readable", then you should learn TypeScript or something like that? This is exactly what you want https://www.typescriptlang.org/docs/handbook/classes.html
@whoizit "Go use another language" - really not constructive. See also this.
@mindplay-dk I decided not to change anything for now. I realized I was spending too much time on this. I need to finish lots of projects before the end of April.
It will be trivial to change the syntax in the future with the help of vfmt
, which is called on every run of the program.
I have a small suggestion, if you should choose to go the symbol route. I know that there was some discussion about using '!' with generic types, but what about prefixing ann identifier with an exclamation for external visibility (exported)?
struct Foo {
private int
!length int // exported read-only
mut !bar int // exported and mutable
}
But I rather prefer:
struct Foo {
private int
length! int // exported read-only
mut bar! int // exported and mutable
}
This idea is derived from Dylan, where it is convention to end a binding identifier with '!' if it destructively modifies its arguments.
The syntax has been decided. Thanks for your input.
Here's what I currently have in mind:
What do you think?
edit
Slight improvement:
edit 2
Immutable struct fields by default got a lot of support: