racket / rhombus

Rhombus programming language
Other
344 stars 62 forks source link

Make an RFC for naming convention #49

Closed sorawee closed 2 months ago

sorawee commented 5 years ago

Per @dedbox's suggestion

Naming Convention

Naming convention Description Example
Ends with ? predicates and boolean-valued functions boolean?
Ends with ! setters and field mutators set!
Ends with % classes game-state%
Ends with <%> interfaces dc<%>
Ends with ^ unit signatures game-context^
Ends with @ units testing-context@
Begins with #% kernel identifiers #%app
Has / "with" (a preposition) call/cc
Begins with make- generative constructors make-pipe
Begins with with- forms that have internal def body with-limits
Begins with call-with- function variants of with- call-with-limits
Begins with current- parameters current-compile
Ends with =? equality functions string=?
Ends with -ref accessors (non-destructive) hash-ref
Ends with -set setters (non-destructive) hash-set
Ends with -set! setters (destructive) hash-set!
Ends with * variants of non-* let*
Ends with /c contracts list/c
Has -> "to" number->string
Has + "and" gen:equal+hash
Begins with gen: generics gen:equal+hash
Begins with prop: properties prop:procedure
Begins with define definition forms define/contract
Ends with -values multiple values variants define-values
Begins with in- sequences in-slice
Begins with splicing- splicing forms splicing-let

Discrepancies / Issues

Let me know if I missed anything, and I will add it to the table.

sorawee commented 5 years ago

Cross-ref: #16, #47

rocketnia commented 5 years ago

Contracts often end with /c with the exception of those that end with of or begin with ->.

Functions that process values of a certain type usually have names that begin with that type. Functions that pass them through to another type in some canonical way are often given names of the form a-type->another-type.

Definition forms often begin with define-.

Getters that have corresponding setters often use the suffix -ref to correspond with -set! or -set.

AlexKnauth commented 5 years ago

The hash-equal? function is confusing because it doesn’t ask whether two hash-tables are equal, as you would expect from the conventions above. Instead it asks whether a single hash-table uses equal? as its key-comparison predicate.

AlexKnauth commented 5 years ago

For the #% prefix, it doesn’t go on all kernel forms, but it does go on all interposition point forms. These are forms that can be overridden by a module-language to take over the meaning of that form within a module. Because of this, the #%app, #%module-begin, #%datum, etc. forms in Racket are macros and do not come from the kernel.

sorawee commented 5 years ago

@AlexKnauth I used the word "kernel" following https://docs.racket-lang.org/style/Textual_Matters.html#%28part._names%29. I guess it includes identifiers that the macroexpander treats specially.

sorawee commented 5 years ago

Another issue related to this:

For sets, we have: set (which is immutable), mutable-set, weak-set.

For hash maps, we have: hash (which is immutable), make-hash, make-immutable-hash, make-weak-hash.

We should make them consistent.

(from #29)

jackfirth commented 5 years ago

I think a good next step for this issue would be to make a list of possible name changes for identifiers in racket/base, so we can test how these conventions would work out on actual code.

AlexKnauth commented 5 years ago

For the with- and call-with- conventions

For many of these renames from with- to call-with-, a macro version that accepts a body should be added if it doesn't exist already.

with-check-info* rename -> call-with-check-info* with-default-check-info* rename -> call-with-default-check-info* with-errors-to-browser rename -> call-with-errors-to-browser with-input-from-bytes rename -> call-with-input-from-bytes with-input-from-string rename -> call-with-input-from-string with-output-to-bytes rename -> call-with-output-to-bytes with-output-to-string rename -> call-with-output-to-string with-input-from-url rename -> call-with-input-from-url (from picturing-programs, but maybe we could have something like this in racket2) with-installer-window rename -> call-with-installer-window with-intercepted-logging rename -> call-with-intercepted-logging with-logging-to-port rename -> call-with-logging-to-port with-module-reading-parameterization rename -> call-with-module-reading-parameterization

with-continuation-mark extend to allow internal definitions with-immediate-continuation-mark should exist and allow a body with internal definitions with-default-reading-parameterization should exist and allow a body with-check-info* should be a macro-with-body version of call-with-check-info* with-trusted-sandbox-configuration exist and allow a body with-semaphore should exist and allow a body

For the #% convention

I believe #%plain-lambda, #%expression, #%variable-reference, #%require, #%provide, and #%declare should be renamed to remove the #% prefix, since they are not override-able like the interposition point macros. They don't act like hooks.

The interposition point macros should keep the #% prefix, such as #%app, #%datum, #%module-begin, #%top, #%top-interaction, #%dot, and #%namespaced.

I believe the #% convention should be separated from the "kernel form" meaning, because languages usually define their own non-kernel versions of the interposition point macros to override behavior. So currently most kernel forms don't actually use #% (and that shouldn't be changed), and most #% definitions are actually non-kernel interposition point definitions for languages.

For the -equal? convention

Functions using a comparison predicate as a suffix that aren't comparison predicates themselves should get out of the way and be renamed:

hash-equal? rename -> hash-uses-equal-key-comparison? or something hash-eqv? rename -> hash-uses-eqv-key-comparison? hash-eq? rename -> hash-uses-eq-key-comparison?

For actual equality functions, I like the concept of "equal now" vs "equal always" from Pyret as in https://github.com/racket/racket2-rfcs/issues/16#issuecomment-512060826 and https://www.pyret.org/docs/latest/equality.html, so:

equal? rename -> equal-now? eqv? delete eq? rename -> identical? or same-object?

Add a new predicate named equal? corresponding to "equal always" that uses structural equality (extensional) for immutable values, and reference equality (intensional, but at least looking through chaperones) for mutable values. So at the end of that we have:

And this should also include equal-now-hash-code, equal-hash-code, and identical-hash-code, and corresponding hash-tables.

For the splicing- convention

begin should be split into two forms:

As raised by https://github.com/racket/racket2-rfcs/issues/87

For the immutable- and mutable- conventions

Immutability should be the default, so:

make-hash rename -> make-mutable-hash make-string rename -> make-mutable-string build-string rename -> build-mutable-string make-vector rename -> make-mutable-vector build-vector rename -> build-mutable-vector

And of course make-hash should be changed to make an immutable hash, make-string should make an immutable string, and so on.

For the -map convention

vector-map should return an immutable vector hash-map should return a hash of the same kind dict-map should return a dict of the same kind set-map should return a set of the same kind free-id-table-map should return a free-id-table bound-id-table-map should return a bound-id-table

perhaps the current set-map, hash-map, etc. operations should be renamed to set-map->list and hash-map->list, to express that they return lists instead of the original data type

sorawee commented 4 years ago

There's also an inconsistency in char/string case manipulating functions:

A better set of names might be:

cloudhan commented 4 years ago

As a non-Scheme/Racket programmer, or more specifically, a programmer comfort with C++ or python, I take this type of character usage as abusing. You can simply naming something without these character. E.g. for boolean?, you just type is_boolean, note you might want to use is-boolean but it will be ambiguous with variable is minus variable boolean, unless you want to enforce whitespace delimited tokens.

AlexKnauth commented 4 years ago

I would prefer whitespace-delimited tokens. Well, whitespace, parens, brackets, braces, quotes, and commas, like racket already does.

I like ?, -, /, >, and other characters in my identifiers as normal characters, not token delimiters. Whitespace is more readable and better style anyway

tgbugs commented 4 years ago

Python has been my primary language for nearly 10 years, and I have come to loath the fact that my identifiers are restricted. This is not just a cosmetic matter, it means that when converting between strings and identifiers (which happens in python and tends to happen in Racket even more frequently), you have to choose some conversion convention for how to make a safe identifier, many people (including myself) have come up with conventions that cannot be inverted. Aside from the fact that writing 1/2 without spaces is awful for readability (and thus that whitespace-plus delimitation promotes basic readability), splitting on operators no matter where they are is just lazy on the part of the language designer because it means that don't have to implement special parsing for operators as operators always have the highest precedence. We don't have to do that here and make users suffer for the rest of the life of the language.

jackfirth commented 4 years ago

writing 1/2 without spaces is awful for readability

Agreed, though Racket already parses that as a literal rational number. The restriction on operators and whitespace is more about things like x/2 or 3/x. If the numerator and denominator are both literal numbers, the parser doesn't need to emit an operator call expression at all and can instead just emit a literal rational. Same thing goes for negation, e.g. -12 is fine but -x is not.

sorawee commented 4 years ago

Another one: mcons -> mutable-cons (or mutable-pair, see #21) to be consistent with, say, mutable-set.

97jaz commented 4 years ago

Struct instance constructors? They used to follow the make- convention but they haven't for a long time. (Circa Racket 5.0, maybe?)

jackfirth commented 4 years ago

Struct instance constructors? They used to follow the make- convention but they haven't for a long time. (Circa Racket 5.0, maybe?)

I think it depends what the struct is used for. When bundling together plain data, I usually omit the make- prefix. But if the struct contains opaque behavior (such as functions) or mutable state, I usually keep the prefix. This helps me tell whether I'm working with pure values or with encapsulating objects.

mflatt commented 2 months ago

527