icerpc / icerpc-csharp

A C# RPC framework built for QUIC, with bidirectional streaming, first-class async/await, and Protobuf support.
https://docs.icerpc.dev
Apache License 2.0
105 stars 13 forks source link

Normalize case for generated identifiers #17

Closed bernardnormier closed 3 years ago

bernardnormier commented 5 years ago

Each programming language has its own preferred case convention for identifiers, in particular for member functions/methods and data members/fields/properties/instance variables:

The Slice compilers currently don't change the case of identifiers in the generated code: if you create an interface MyInterface in Slice, you'll get MyInterface in all programming languages. Likewise, if you define an operation myOp (camelCase), you will get a myOp function/method for your proxies and skeletons in all programming languages, and it will look odd in C# and Python.

The Slice naming convention used by ZeroC for Ice and the Ice demos is:

Ice users are of course free to use whichever naming convention they prefer. For example, it's fairly common to use PascalCase for operation names in Slice and get the same case in the resulting methods/functions.

It would be nice if the generated identifiers could respect the preferred naming convention of each language, instead of generating good looking identifiers in some languages and odd-looking names in other languages.

Proposed solution Add file metadata directives that "normalizes" the case of generated identifiers. The default (without metadata) would be the current behavior: keep the identifiers as-is.

To keep things reasonably simple, I propose a single per-language switch: either the Slice compiler keeps all the identifiers as is, or it normalizes all the identifiers. For example, you would not be able to tell the compiler to normalize the generated identifiers for your operation names but not for your data member names. Furthermore:

In other words, this new metadata would affect only the mapping for operation names, data members names, enumerators and constants. In most languages, there would be only one option, for example:

[["java:normalize-case"]] // mapped methods and fields are camelCase
[["cs:normalize-case"]] // mapped methods and properties are PascalCase
[["swift:normalize-case"]] // mapped functions and properties are camelCase
[["python:normalize-case"]] // mapped methods and instance variables are snake_case

In C++, where there is no universal naming convention, the metadata would include the desired convention:

["cpp:normalize-case:camelCase"]] // mapped functions and data members are camelCase
["cpp:normalize-case:PascalCase"]] // mapped functions and data members are PascalCase
["cpp:normalize-case:snake_case"]] // mapped functions and data members are snake_case
Lastique commented 4 years ago

I think, I'd prefer to have a command line argument to select the naming convention on translation instead of putting directives in all .ice files.

bernardnormier commented 4 years ago

I think, I'd prefer to have a command line argument to select the naming convention on translation instead of putting directives in all .ice files.

With the metadata directive(s) directly in the Slice file, you see immediately how this Slice file gets mapped to all language mappings. Using an option to the Slice compilers hides this mapping. For example, we will most likely add the metadata directive ([["normalize-case"]]) to all the Slice files included in Ice, such as Ice/Locator.ice and IceGrid/Admin.ice.

I don't see an obvious use-case for the Slice compiler command-line option. Different groups within a company use different identifier case conventions?

Can you shed light on your use-case?

Lastique commented 4 years ago

The mapping is each user's preference. It follows from coding conventions in the particular project that consumes the generated Slice API. These conventions may be different in different projects on the same language, even within the same company. Note that the Slice API may be published beyond company as well.

Another point for the compiler option is that the option can be specified once in the build system in the Slice generator command line, instead of putting it in every .ice file you have to translate and keeping it consistent everywhere.

pepone commented 3 years ago

Already done for IceRpc C#