blob: 2afd6f0d077f0c75a76305849accb206aca8d775 [file] [log] [blame] [view] [edit]
## Syntactic and semantic differences between Java and the generated Dart bindings
This document highlights the key syntactic and semantic variations between Java
and Dart and how JNIgen addresses them to ensure smooth interoperability.
### Method overloading
Java supports overloading methods. This means that it can distinguish between
two methods with the same name that have a different signature.
```java
// Java
public class Calculator {
public int add(int a, int b) {
return a + b;
}
public double add(double a, double b) {
return a + b;
}
public float add(float a, float b) {
return a + b;
}
}
```
This is not the case for Dart. Each method of a class must have a unique name.
To overcome this limitation, JNIgen adds a dollar sign (`$`) and a numeric
suffix to the end of the overloaded method name.
```dart
// Dart Bindings - Boilerplate omitted for clarity.
class Calculator extends JObject {
int add(int a, int b) { /* ... */ }
double add$1(double a, double b) { /* ... */ }
double add$2(double a, double b) { /* ... */ }
}
```
> [!WARNING]
> Running the code generator again on a different version of the library can map
> the methods differently if the order of the methods change or another
> overloading of the same method gets added.
>
> Double check the doc comments on the generated methods to make sure you are
> calling your intended method.
You might wonder why the method isn't renamed to `add1` instead of `add$1`. The
reason is that a method named `add1` could already exist in the Java class. On
the other hand, Java identifiers normally do not contain dollar signs.
> [!NOTE]
> See
> [Identifiers containing dollar signs](#identifiers-containing-dollar-signs) to
> see what JNIgen does when identifiers contain dollar signs.
```java
// Java
public class Calculator {
public int add(int a, int b) {
return a + b;
}
public double add(double a, double b) {
return a + b;
}
public float add(float a, float b) {
return a + b;
}
public int add1(int a) {
return a + 1;
}
public double add1(double a) {
return a + 1;
}
}
```
In this case, the generated code will be:
```dart
// Dart Bindings - Boilerplate omitted for clarity.
class Calculator extends JObject {
int add(int a, int b) { /* ... */ }
double add$1(double a, double b) { /* ... */ }
double add$2(double a, double b) { /* ... */ }
int add1(int a) { /* ... */ }
double add1$1(double a) { /* ... */ }
}
```
### Fields and methods with the same name
In Java, we can have a field and a method with the same name. This is not
possible in Dart.
```java
// Java
public class Player {
// Player's personal duck!
public Duck duck;
// Lower your head!
public void duck() { /* ... */ }
}
```
JNIgen handles this similarly to [method overloading](#method-overloading). The
method with the same name as the field will be appended by a dollar sign (`$`)
followed by a numeric suffix.
```dart
// Dart Bindings - Boilerplate omitted for clarity.
class Player extends JObject {
Duck get duck { /* ... */ };
set duck(Duck value) { /* ... */ }
void duck$1() { /* ... */ }
// If there were more `duck` methods they would be named
// `duck$2`, `duck$3`, ...
}
```
It is important to note that the order of renaming is fields-first
methods-second. So when both a field named `duck` and a method named `duck`
exist, the field keeps its original name as seen above.
However the renaming happens for superclasses first. Consider this case.
```java
// Java
public class Player {
// Lower your head!
public void duck() { /* ... */ }
}
public class DuckOwningPlayer extends Player {
// Player's personal duck!
public Duck duck;
}
```
The `Player` class already has a method named `duck` and no field with the same
name. So this will be the generated bindings for it:
```dart
// Dart Bindings - Boilerplate omitted for clarity.
class Player extends JObject {
void duck() { /* ... */ }
}
```
`DuckOwningPlayer` inherits the `duck()` method from `Player` and adds a field
named `duck`. This time, the field will be renamed as the method is simply
inherited.
```dart
// Dart Bindings - Boilerplate omitted for clarity.
class DuckOwningPlayer extends Player {
Duck get duck$1 { /* ... */ };
set duck$1(Duck value) { /* ... */ }
}
```
### Identifiers containing dollar signs
JNIgen uses dollar signs in the generated code to fill the syntactic and
semantic gaps between Java and Dart. This normally does not cause a problem as
the
[Java language specificifaction](https://docs.oracle.com/javase/specs/jls/se11/html/jls-3.html#jls-3.8)
suggests dollar signs should be used only in the generated code or, rarely, to
access pre-existing names on legacy systems.
JNIgen replaces each single dollar sign with two dollar signs. For example
`generated$method$2` will turn into `generated$$method$$2`. This prevents name
collision as JNIgen-renamed identifiers will end with an odd number of dollar
signs (optionally followed by a numeric suffix).
### Identifier starting with underscore (`_`)
Unlike Java, Dart identifiers that start with an underscore are private. This
means they are inaccessible outside their defining scope. Users should still be
able to access public Java identifiers that start with an underscore from the
generated Dart bindings. To allow this, JNIgen prepends such identifiers with a
dollar sign to keep them public in Dart.
For example, `_Example` in Java will be converted to `$_Example` in the Dart
bindings:
```java
// Java
public class _Example {
public void _printMessage() {
System.out.println("Hello from Java!");
}
}
```
```dart
// Dart Bindings - Boilerplate omitted for clarity.
class $_Example extends JObject {
void $_printMessage() { /* ... */ }
}
```
### Inner classes
Java has the concept of inner classes, while Dart does not. Therefore, inner
classes are generated as separate classes named using the name of their
outer-class followed by a dollar sign (`$`) followed by their original name.
For example:
```java
// Java
public class Outer {
public class Inner {}
}
```
will be turned into:
```dart
// Dart Bindings - Boilerplate omitted for clarity.
class Outer extends JObject {}
class Outer$Inner extends JObject {}
```