Vinícius Jorge Vendramini

Alfredo Goldman

Grégory Mounié
email: gregory.mounie@imag.fr

Improving mobile app development using transpilers with maintainable outputs

Keywords: transpilers, transcompilers, mobile, Swift, Kotlin

Mobile application developers often target both iOS and Android in an effort to extend their target user base. There are several tools that can aid this development effort, allowing developers to maintain a single codebase for both platforms instead of two. These tools often face a few shortcomings, of which two are noteworthy: they are hard-to-replace dependencies in the codebase, and often present some type of obstacle for integrating platform-independent native code with the shared codebase. The goal of this work is to propose a new approach to creating cross-platform development tools that improves on these two aspects, and to analyze the viability of a real-world implementation of the proposed approach. An analysis of the current state of the practice indicates cross-platform compilers as a promising direction, and a study is made on the common concerns and challenges faced when developing these compilers. Based on these analyses, this work proposes the creation of a compiler that translates one platform's hand-written native code into maintainable native code for the other platform. The feasibility of implementating this approach is tested with the development of a proof-of-concept compiler from Swift to Kotlin. An analysis is made on the readability of the resulting prototype's output code, as well as other relevant metrics. The conclusion is that, while some trade-offs might be necessary, such an approach is viable if applied in an adequate ecosystem.

CCS CONCEPTS

• Software and its engineering → Source code generation; • General and reference → Cross-computing tools and techniques.

INTRODUCTION

When developing applications (apps) in any environment, it is common for programmers to target more than one operating system in an effort to expand their potential user base. In the case of smartphones, this usually means offering an app for both Android and iOS. These operating systems can be targeted directly with each platform's software development kit (SDK), which is available only in specific "native" languages: Objective-C and Swift for the iOS SDK, and Java and Kotlin for the Android SDK.

The lack of a common language with direct access to both platforms' SDKs means developers cannot trivially write a single codebase that compiles to both platforms. To ease that task, several authors have created cross-platform development tools that run the same code on both platforms using different approaches. Early versions of these tools created websites stylized look and behave like native applications, "capitaliz[ing] on the good browser support of mobile platforms" [17, p. 122] to make their content portable. Some more modern iterations like ReactNative [START_REF]React Native[END_REF] and Flutter [START_REF]Flutter. Retrieved on 2020[END_REF] achieve portability by implementing their own runtime frameworks that support new languages like JavaScript and Dart on both platforms. Other tools can compile one of Android's native languages into Objective-C (like J2ObjC [START_REF] Google | J2ObjC: Overview[END_REF]) or LLVM (like Kotlin/Native [START_REF] Kotlin | Kotlin/Native[END_REF]), making it available for iOS apps.

All of these approaches have in common the fact that they require developers to write their programs on top of layers of abstraction (such as tool-specific languages and libraries) on which the developer's code depends. This dependency means the code will not work if the layers of abstraction are removed, and instead will have to undergo some sort of migration (which is, in its worst case, a complete rewrite of the application). Additionally, these layers create a gap between shared code and platform-specific code, which can make it difficult for one to access the other.

These problems are not only theoretical -they have been documented in both academic research and industry reports (section 2). Some approaches, however, seem promising for mitigating them. J2ObjC's ability to turn Java code into Objective-C code, for instance, may indicate a solution to the dependency issue. Since the input code can be directly compiled for Android and the output code for iOS, a developer might theoretically be able to maintain them without depending on the tool or having to migrate their code. The main impediment for this is the difficulty in reading and understanding J2ObjC's generated Objective-C code in order to maintain it, as will be shown (section 4.3).

Similarly, KotlinNative's ability to compile Kotlin code into iOS libraries may indicate a solution to the issue of integrating native and platform-specific code. The tool's generated iOS libraries offer APIs that include several usability annotations and follow idiomatic conventions, which contribute to making them easier to call from platform-specific code. However, this integration only works one way: KotlinNative's libraries cannot directly access the native code that calls them, they can only access native frameworks that have been compiled separately.

This study proposes a new approach to creating cross-platform development tools, by improving on existing models using strategies discussed in the literature. The suggested improvements enable a development tool to both avoid becoming a dependency for a project and offer seamless integration between platform-specific and shared code.

First, this definition is constructed from an analysis of existing cross-platform development tools, and the strategies to achieve it are selected from related practical and academic works (section 2). Next, the methodology is presented -specifically, how the selected strategies were used to directly pursue the goals mentioned above (section 3). Finally, an implementation is presented as a proof of concept, and there is a discussion on how the strategies were applied in this case and on the tests performed on the implemented program (section 4).

RELATED WORKS 2.1 Cross-platform development tools

As the main alternative for native development, tools for the implementation of web apps, hybrid apps, and other non-native approaches account for numerous practical and academic works in mobile development.

In practice, several tools enable developers to create cross-platform apps by developing their code in one of several non-native languages. For instance, PhoneGap allows users to create "hybrid applications built with HTML, CSS, and JavaScript" [START_REF]Adobe PhoneGap[END_REF]; React Native enables the creation of apps "using only JavaScript" with "the same fundamental UI building blocks as regular iOS and Android apps" [START_REF]React Native[END_REF]; and XMLVM can "cross-compile" an Android application so that it will run on iOS [START_REF] Puder | Cross-Compiling Android Applications to iOS and Windows Phone 7[END_REF]. Similarly, the academic literature includes several studies that propose the creation of development tools using new domain-specific languages, such as md2 [START_REF] Heitkötter | Cross-platform Model-driven Development of Mobile Applications with Md2[END_REF], ScaMo [START_REF] Macos | ScaMo: Realisation of an OO-functional DSL for cross platform mobile applications development[END_REF], Xmob [START_REF] Le Goaer | Yet Another DSL for Cross-platforms Mobile Development[END_REF], ICPMD [START_REF] El-Kassas | ICPMD: Integrated cross-platform mobile development solution[END_REF], and the Common framework [START_REF] Perchat | Component based Framework to Create Mobile Cross-platform Applications[END_REF][START_REF] Perchat | Common framework: A hybrid approach to integrate cross-platform components in mobile application[END_REF].

In a more native setting, JetBrains developed a Kotlin compiler for iOS called Kotlin/Native [START_REF] Kotlin | Kotlin/Native[END_REF], which can create iOS libraries with reasonably idiomatic APIs for Objective-C and Swift. Kotlin/Native libraries can only access native iOS code that has itself been compiled into libraries, which limits the possibilities for native and non-native code integration. Additionally, because the Kotlin code is compiled into binary libraries, the iOS version still depends on Kotlin/Native to be maintained.

Developers at Dropbox have taken a different approach, implementing their shared logic using C++ [START_REF] Guthmann | The (not so) hidden cost of sharing code between iOS and Android[END_REF]. Because C++ is available on both platforms, the code can be compiled natively and is maintainable without any external dependency; however, it does not have direct access to the native SDKs (which are only available in Java, Kotlin, Objective-C and Swift), so it faces the same integration problems mentioned above. Similarly, developers at Readdle [START_REF] Readdle | Swift for Android: Our Experience and Tools[END_REF] use Swift code on both iOS and Android, but the Android version cannot directly access the native SDKs.

Google's J2ObjC [START_REF] Google | J2ObjC: Overview[END_REF] also allows developers to maintain a native codebase. By translating Java source files into Objective-C, the tool ensures Android apps do not depend on it to be maintained, as the Java codebase can be compiled directly. The iOS apps, however, are built with the translated Objective-C code (which can be "ugly" and "hard-to-read" [START_REF] Ball | cfront: a J2ObjC Inspiration[END_REF]) and have to be linked against J2ObjC's implementation of the Java standard library for iOS, making them dependent on the tool. That said, J2ObjC's model seems to show the most promise in solving these dependency and integration issues, and therefore was used as a starting point for the proposal in this work.

Transpilers

Transpiler is the name given to a compiler that translates code from a language with a high level of abstraction into another. For example, while a tool that turns C++ code into machine code might be called a compiler, one that turns Java code into Objective-C (like J2ObjC above) might be called a transpiler.

Researchers have been studying transpilers at least since the 1980's, with the works of Wallis [START_REF] Wallis | Automatic Language Conversion and Its Place in the Transition to Ada[END_REF] and Albrecht et al. [START_REF] Albrecht | Source-to-source Translation: Ada to Pascal and Pascal to Ada[END_REF] using Ada. More recently, some studies have also focused on different uses for transpilation, which include performing compiler optimizations [START_REF] Yi | POET: A scripting language for applying parameterized source-tosource program transformations[END_REF], translating between more than two languages with similar paradigms, [START_REF] Arrighi | The GOOL System: A Lightweight Object-oriented Programming Language Translator[END_REF][START_REF] Schaub | The Design and Evaluation of an Interoperable Translation System for Object-Oriented Software Reuse[END_REF] and creating new languages that ease correctness proofs for programs [START_REF] Plaisted | Source-to-source translation and software engineering[END_REF]. Some authors, like Huijsman, van Katwijk, Pronk, and Toetenel, have studied transpilers as a way of helping developers permanently migrate a codebase from one language to another [START_REF] Huijsman | Translating Algol 60 Programs into Ada[END_REF]. These transpilers prioritize their output code's readability over preserving the input code's semantics, a method that allowed developers to understand the translated code and fix its bugs during the migration process (but that is not as well-suited for day-to-day compilations). This model is used today by some transpilers of mobile app languages, like SwiftKotlin [START_REF] Olloqui | SwiftKotlin. Retrieved on 2020[END_REF] and Kotlift [START_REF] Moshbit | Kotlift[END_REF].

Other transpilers were designed to be a part of a developer's day-to-day compilation cycle, and as such prioritize preserving the input code's semantics so that the output code does not have to be edited after translation. This is the case with J2ObjC. Schaub and Malloy notably developed a semantics-preserving transpiler between Java, C++ and Python that aimed to produce readable code [START_REF] Schaub | The Design and Evaluation of an Interoperable Translation System for Object-Oriented Software Reuse[END_REF]. Their study highlights the importance of choosing input and output languages with compatible paradigms and semantics, noting that when "source language features are used [...] that are not present in the target language, those features must be emulated [...]; depending on the difficulty of the emulation, the readability [...] of the resulting code can suffer greatly" [35, p. 6].

Schaub and Malloy also mention that "Ideally, a [...] translation should map standard library calls for the source language to the native standard library calls for the target language, rather than introducing an interoperable library layer" [35, p. 6]. This approach was used for the GOOL transpiler's translations [START_REF] Arrighi | The GOOL System: A Lightweight Object-oriented Programming Language Translator[END_REF], which serve as a direct inspiration for this work.

Dependency and integration

The two main problems being investigated in this work involve a tool's dependency -i.e. the fact that codebases depend on the tools in order to be maintained -and integration -i.e. the fact that codebases that use the tools do not have direct access to and from native code. These problems have been reported both by academic researchers and by developers working in well-known applications.

The dependency issue, for instance, has been documented by developers at Facebook, who had to "rebuild" their iOS app's codebase in 2012 [START_REF] Facebook | Under the hood: Rebuilding Facebook for iOS[END_REF]; Dropbox, who in 2019 moved from their model using shared C++ code [START_REF] Guthmann | The (not so) hidden cost of sharing code between iOS and Android[END_REF]; and AirBnB, who went from using ReactNative towards a fully native approach in 2018, saying they expected the process to take over a year [START_REF] Peal | React Native at Airbnb[END_REF].

Similarly, integration issues in tools using non-native approaches have been well documented in the academic literature [5-7, 18, 20, 23, 27]. In particular, several of these authors describe difficulty accessing some of the operating system's functionalities, "such as a camera or a GPS sensor" [17, p. 122]. More native approaches, however, have since improved on this panorama (as described above), making them the basis for this study.

METHODOLOGY

Based on the analyzed works, we can properly define the goals of this work as follows. We propose the creation of a transpiler that:

(1) Prioritizes its output code's maintainability: generated output code should be reasonably understandable, such that a developer that knows the input and output languages and understands the input code can also reasonably understand the output code.

(2) Depends only on maintainable or removable libraries: generated output code should depend only on libraries that are small and understandable enough to reasonably be maintained or removed by an app's developers. (3) Ensures its output code offers idiomatic APIs: generated APIs should follow common platform and language conventions and be directly accessible from platform-specific code, without requiring interoperability layers. (4) Ensures its output code can directly access platformspecific code: platform-specific code written in both the input and output languages should be directly accessible from the shared code.

A developer that creates an app using a transpiler like this can switch to a fully native approach trivially, since the codebases and dependencies for both platforms would be maintainable at all times. This would avoid the migration issues reported by Facebook [START_REF] Facebook | Under the hood: Rebuilding Facebook for iOS[END_REF] and AirBnb [START_REF] Peal | React Native at Airbnb[END_REF], as mentioned above. These goals would also allow platform-specific code and shared code to integrate seamlessly with each other, thus solving our two targeted issues (dependency and integration).

The success of failure of this approach, as with the creation of any transpiler, is highly dependent on the choice of input and output languages. In general, transpilers work better when their languages are more similar, with similar paradigms, memory management techniques, basic semantics, and even syntactic structure. In the case of J2ObjC, Java and Objective-C have many aspects that are alike (such as object-oriented paradigms and reference semantics), but also some that are different (such as their use of namespaces and calling conventions) that can make it more difficult to achieve the goals above.

With this in mind, it was decided that this work's attempt at implementing the proposed approach would be a transpiler from Swift to Kotlin. While these languages have some semantic differences (whose effects will be discussed later), the similarities in their paradigms and syntax made them good candidates for this work.

The proof-of-concept transpiler was itself implemented in Swift, and is called Gryphon. The strategies below illustrate ways in which Gryphon's design builds on J2ObjC's. Most of them were (either directly or indirectly) inspired by transpilers from the literature.

Strategies for improving code maintainability:

Avoiding significant structural modifications: occasionally, transpilers need to significantly modify the structure of the input code in order to guarantee the same behavior in the output code (see J2ObjC's example in section 4.3). That can lead to problems such as misplaced comments, variable names that do not make sense when out of order, etc. Structural modifications in Gryphon are limited to changes that do not modify blocks of statements, such as:

• adding declarations, like automatic implementations of Swift's rawValue initializers for Kotlin's enum classes; • moving entire declarations, like placing Swift's static functions inside Kotlin's companion objects; • or changing a declaration's interface, like turning Swift's "var description" into Kotlin's "fun toString()".

Idiomatic translations: input and output languages often have different conventions and mechanisms concerning how to execute certain tasks, how to name certain structures, etc. Some of these differences require changes because they can affect the code's behavior: in the example above, Swift's "var description" has to be translated as Kotlin's "fun toString()" because these are the interfaces that are accessed when an instance has to be turned into a string.

Other cases involve more aesthetic changes that have the same behavior but can make the output code easier to understand by conforming to community conventions. For instance:

// Swift guard x != nil else { return } // Kotlin translation (Swift-like) if (x != null) { return } // Kotlin translation (idiomatic)
x ?: return Style: certain aspects of coding style can be applied to the output code after the translation using tools called linters (for instance, the Kotlin community has a linter called ktlint [START_REF] Pinterest | ktlint: An anti-bikeshedding Kotlin linter with built-in formatter[END_REF]). Some coding style aspects that are not enforced by a language's linter can be enforced by the transpiler. For instance, ktlint does not check for the maximum number of characters in a line of code, but Gryphon can limit this by adding newlines when translating function calls, closure declarations, etc.

Comments: source code comments are kept during the translation and placed somewhere as similar to the input code as possible. Albrecht et al. [START_REF] Albrecht | Source-to-source Translation: Ada to Pascal and Pascal to Ada[END_REF] perform this task with mixed results by linking comments to nearby statements so that they move along with the code they (hopefully) refer to; inspired by that, Gryphon turns comments into their own statements, which allows them to be moved cohesively or independently as needed.

Formatting: any additional formatting details should be mimicked in each case whenever possible. This includes factors like the amount of whitespace separating groups of statements or declarations, consistently labeling parameters in function calls, etc.

Names: the names of types, variables, and other declarations stay the same whenever possible. This rule takes less precedence over others (for instance, names can be capitalized or otherwise changed to become more idiomatic), but these modifications take care not to change or lose the meanings of the given names.

Strategies for improving library maintainability:

Size: any libraries necessary for the input and output codes to compile were be designed to be as small as possible, to make it easier for developers to maintain or remove them at will.

Transpiler libraries for both languages: transpilers that do not prioritize maintainability often provide a library only for the output language. This allows their users to write the input code without having to learn to use any transpiler-specific libraries, but it also limits the transpiler developers to having access to custom code only in the output language. Gryphon does not abide by this restriction: since the transpiler's libraries are designed specifically to be small and maintainable, it is considered acceptable that the transpiler's users learn to use them. This provides some leeway on the implementation that allows for a more effective the use of the other strategies, particularly when translating references to the languages' standard libraries.

Native translations: similar languages may also have similar standard libraries, which may allow references to the input language's library to be translated to references to the output language's library. This idea was implemented in the GOOL transpiler [START_REF] Arrighi | The GOOL System: A Lightweight Object-oriented Programming Language Translator[END_REF], which used files written in a domain-specific language to specify mappings for classes and methods. A similar strategy was used for Gryphon, with the difference that the mappings were written directly in the input language, which allows them to be defined for arbitrarily complex Swift expressions (instead of just class and method names). Similarly, the method for specifying their Kotlin translations was made more complex by allowing them to be declared both as literal strings or as more complex structures -which can give Gryphon valuable information on the translations to avoid bugs: // Swift expression _string.formIndex(before: &_index) // Kotlin translation "_index -= 1" // Swift expression _string1.replacingOccurrences( of: _string2, with: _string3) // Kotlin translation Template.call(.dot( "_string1", "replace"), ["_string2", "_string3"]) // Swift expression Range<String.Index>(uncheckedBounds: (lower: _index1, upper: _index2)) // Kotlin translation Template.call("IntRange", ["_index1", "_index2"])

Strategies for improving access in platform-specific code to shared declarations:

Readable API:. in addition to the idiomatic translations mentioned before, any declarations that are accessible to the platformspecific code (that is, all declarations that are not marked as private) need to offer readable and idiomatic APIs. This includes details like the translation of function labels: Swift's convention is that they should form a sentence-like function call, but Kotlin's convention is that they correspond to the parameter names used in the implementation: Gryphon keeps track of all function declarations (and their parameters' internal names) in order to translate function calls correctly when they show up in the same file or in other files.

Access control: access control modifiers are translated into their Kotlin counterparts in most cases; when there is no counterpart (e.g. some uses of Swift's fileprivate modifier have no equivalent translation in Kotlin), Gryphon defaults to the next less restrictive option. This avoids platform-specific code accessing a declaration it should not on most cases while also avoiding compilation errors due to inaccessible declarations on the edge cases. Gryphon also omits the access control keywords whenever possible to avoid cluttering the output code.

Open and final: translations for classes and their members include open or final modifiers to avoid platform-specific code creating subclasses where it should not. These modifiers are also omitted whenever possible to avoid cluttering the output code.

Strategies for improving access in shared code to platform-specific declarations:

Mappings: any platform-specific declarations that have the same APIs on both platforms can be trivially accessed by translated code. When the APIs are different, the same mapping system used for translating references to the Swift standard library can be used by developers to define translations from input to output APIs.

Manual translations: in cases where the shared code should behave differently in each platform, a manual translation system can use special comments to arbitrarily ignore Swift statements or insert Kotlin statements. Specifically, this system can be used to ignore calls to iOS-only APIs and insert calls to Android-only APIs: // Swift iOSOnlyFunction() // pegasus ignore // pegasus insert: androidOnlyFunction() let language = "Swift" // pegasus value: "Kotlin" // Kotlin (Gryphon translation) androidOnlyFunction() let language = "Kotlin"

This system can also be used to fix limitations on Gryphon's current translation system, such as adding override keywords to methods that satisfy protocol requirements (the information for which is not trivially available in Swift).

RESULTS

As a proof-of-concept implementation for this work, Gryphon is an open source project and is available on GitHub [START_REF] Vendramini | Gryphon: The Swift to Kotlin translator[END_REF]. The studies discussed in this section were performed on a closed beta version (v0.3). Gryphon has since been released to the public, and its updates are downloaded by dozens of users weekly (according to GitHub's traffic data for the repository).

As mentioned before, it is important to study what effects the strategies outlined in this work might have had on Gryphon's design. The studies below aim to do that by considering different metrics that are used in related works, such as the performance of the output code, the support of different features in the input language, etc.

Bootstrapping

Some early studies on Gryphon's viability involved attempts to translate parts of open-source iOS apps into corresponding parts of their Android versions. These attempts largely failed because of the difficulty in finding appropriate candidates. There were few wellknown apps using Swift and Kotlin and that open-source enough of their codebases to compile and run all automated tests, and those that existed tended to have different architectures for iOS and Android (meaning the translated code would not fit with the rest of the Android application).

Instead, Gryphon's own source code proved to be a viable target for translation. It had been implemented using Swift features that were mostly already supported, meaning relatively little adaptation was required. Possibly the greatest challenge was that, because the transpiler was still being developed, it did not include some features it needed to translate itself -and every feature implemented meant more code that needed to be translated.

This process of having a compiler or transpiler work on its own code is known as bootstrapping. Once the bootstrapping process This way, the bootstrapping process helps check if the transpiler works as intended: it ensures that enough Swift features are supported to translate its own source code, and it ensures that the behavior of the output code is the same as that of the input code to the extent that it passes the same automated tests.

Table 1 provides numbers on the amount of source lines of code involved in both the translated and platform-specific source files. The codebase includes 11 397 lines of code in files that it automatically translates to Kotlin (representing 97.78% of the total) and 259 (2.22%) in files that are exclusive to the Swift version (whose Kotlin counterparts are manually maintained). The translated Kotlin version is made up of 10 986 lines of code from translated files (representing 98.11% of the Kotlin codebase) and 212 (1.89%) from Kotlinexclusive files.

Most of the translated files in the Swift version use manual translation comments, as detailed in table 2. Of the 11 397 source lines of code in those files, 352 of them (3.09%) use these mechanisms. This includes 74 manual insertions; 23 manual deletions; and 255 comments used for different tasks, such as adding override annotations to satisfy protocol conformances, etc. Further development efforts have since decreased these numbers by automatically handling some of these cases.

These line counts were done by removing all lines that were empty or contained only comments, as well as 9 lines of Kotlin code that were used only for calling the tests. It is worth noting that some translations to Kotlin result in more lines of code than their Swift counterparts, while the contrary is less common. The slight reduction on the number of lines of code in the Kotlin version (table ) is likely due to other factors such as differences in code styles, in the amounts of newlines, etc. Gryphon's required libraries are comprised of one Swift file and one Kotlin file, to be added to the iOS and Android apps respectively. The Swift file contains 649 lines of code, including 227 lines implementing the 105 standard library translations, and 422 implementing wrappers for collections. With regard to maintainability, the 227 lines implementing translations have no behavior and can be deleted safely; and the 422 lines of wrappers include only oneline methods1 that redirect to calls to native implementations.

The Kotlin file focuses on providing Kotlin implementations of some Swift algorithms that were deemed too complex or too verbose to replicate inline without the aid of additional implementations. It contains 60 lines of code divided into seven methods. Three of these methods, like their Swift counterparts, contain exactly one line of code; three of them comprise an implementation of the quicksort algorithm; and one searches for a character in a string.

Table 3 and table 4 show how many statements, declarations and expressions of each kind are currently present in Gryphon's source code. They give a sense of what kinds of Swift features are currently supported and how often they appear. Some of them have noteworthy details or explanations, described below.

Expression Statement: corresponds to an expression that acts as a standalone statement -e.g. calling a function like print("Hello!"). Closure Expression: Swift's closures are translated into lambdas in Kotlin. This includes the translation of anonymous parameters when possible (i.e. Swift's $0 to Kotlin's it). One of the challenges with this translation involves returning from closures: while return statements exit the closure in Swift, they exit the innermost function declaration in Kotlin. To get the same behavior, Gryphon currently scans the function that is calling the lambda and adds explicit labels to any return statements it finds. Literal Code Expression: an expression corresponding to code that has been literally translated or inserted into the output. This means both code that a developer inserted manually and translations that involve literal code, such as references to the Kotlin standard library.

// Swift

Optional Expression: Optional expressions specify when a value with an optional type (i.e. a type that can either be present or be null) is being evaluated. Their translation is particularly complicated in optional evaluation chains, which have to be propagated from Swift to Kotlin.

If Expression: If statements in Kotlin can be used as expressions; this is particularly useful in this case because it allows Swift's ternary operator to be translated (since Kotlin itself does not support a similar operator).

// Swift let language = isIniOS ? "Swift" : "Kotlin" // Kotlin (Gryphon translation) val language: String = if (isIniOS) { "Swift" } else { "Kotlin" } ↩→

Benchmarks

In order to ensure the proof-of-concept transpiler could be used to generate output code with reasonably acceptable performance, a series of benchmark tests were used. The benchmarks were taken from the Computer Languages Benchmark Game's catalog, which has been used previously in other research [START_REF] Gouy | The Computer Language Benchmarks Game[END_REF]. It provides a set of toy programs implemented in different programming languages, which notably include Swift and Java. The purpose of this study was to analyze the performance characteristics of code that had not been specifically optimized (as performance-critical code can be implemented in platform-specific files). Therefore, heavily-optimized examples were discarded, leaving five programs: binary-trees, fannkuch-redux, mandelbrot, n-body, and spectral-norm. Four versions were created for each program: hand-written Swift and Kotlin, and Gryphon-compatible Swift and The benchmarks were executed 600 times for each version of each program. All of the data from the experiments, as well as the source codes for the benchmarks, are publicly available [START_REF] Vendramini | Research data on the Gryphon transpiler[END_REF].

The results are summarized on tables 5 and 6. Notably, times for the Gryphon-compatible Swift version ranged from a 0.39% speedup to a 0.56% slowdown, and times for the Gryphon-translated Kotlin version ranged from a 0.14% speedup to a 3.01% slowdown. These numbers are interpreted here as an indication that if any performance regressions did happen they are likely to be acceptable to most users.

Maintainability

Formally testing the maintainability of the proof-of-concept's output would involve testing how well production code for realistic applications can be modified and evolved by developers over time, which is outside of the scope of this work. Rather, the focus here is on the code's perceived readability, as well as on numerical analyses related to both its size and how much of it can be translated.

An early attempt at determining readability involved an online survey, which asked participants to rate the readability of the same algorithm implemented in Swift, Kotlin, Java and Objective-C, including versions that used Gryphon. This survey was not answered by enough developers for a statistically significant result, and so it is not included in this text, but the results are available in the accompanying material. In particular, comments on the survey suggested developers' main concerns were the chosen language and the algorithm's documentation.

Following these experiments, a handful of the authors' colleagues and peers suggested that Gryphon's readability improvements would be self-evident in comparison with a transpiler that did not prioritize readability. As such, the code snippets below compare a translation using Gryphon with one using J2ObjC (which served as as the next-best alternative for solving these issues. The relative simplicity and readability that were demonstrated indicate that programs that use Gryphon can depend relatively little on the transpiler: the output code is reasonably readable and concise, and the transpiler's libraries are reasonably maintainable or removable. Additionally, the transpiler's generated APIs and its manual translation mechanisms allow for seamless integration with native code. Finally, quantitative tests indicate that pursuing these goals did not cause significant regressions in other aspects of the translation process, like the generated code's performance.

Recommended directions for further works involve other implementations of this approach (especially using other language combinations that might fare better in some semantic aspects) and testing this approach in more realistic situations, particularly involving real mobile apps (so that there may be a better understanding of its limitations).

  // Swift func addOne(to number: Int) -> Int { return number + 1 } addOne(to: 10) // Kotlin fun addOne(number: Int): Int { return number + 1 } addOne(number = 10)

[ 1 , 2 , 3 ]

 123 .map { return $0 + 1 } // Kotlin (Gryphon translation) listOf(1, 2, 3).map { return@map it + 1 } Tuple Expression: Swift supports tuples as native types, functioning similarly to anonymous structs; Kotlin does not support tuples natively, but it does offer a Pair type in its standard library that serves as a translation for tuples with two elements. Tuples are also used to list parameters in most function calls. // Swift let tuple: (Int, Int) = (1, 2) print(tuple.0) print(tuple.1) // Kotlin (Gryphon translation) val tuple: Pair<Int, Int> = Pair<Int, Int>(1, 2) println(tuple.first) println(tuple.second) Tuple Shuffle Expression: appear when on function calls that include parameters with default values (which can be omitted) or variadic parameters (which can receive multiple values). In particular, the Kotlin translation has to omit labels before variadic parameters on function calls. // Swift func tupleShuffle(a: Int, b: Int..., c: Int = 0) { } tupleShuffle(a: 1, b: 1, 2, 3) tupleShuffle(a: 1, b: 1, 2, 3, c: 1) // Kotlin (Gryphon translation) fun tupleShuffle(a: Int, vararg b: Int, c: Int = 0) { } tupleShuffle(1, 1, 2, 3) tupleShuffle(1, 1, 2, 3, c = 1)

Table 1 :

 1 Number of source lines of code (SLOC) in the Swift and Kotlin versions of the Gryphon codebase.

	Swift project Kotlin project

Table 2 :

 2 Number of source lines of code (SLOC) with manual translation comments in the Swift project. Includes lines that are inserted, ignored or replaced, or lines with annotations like open and override.

		Inserted Ignored Replaced Annotated Total
	SLOC	74	23	12	243	352
	% of total	0.65%	0.20%	0.11%	2.14% 3.09%

had been implemented, the automated unit, integration and acceptance tests were translated by hand into Kotlin so that they could test the translated code. This then became part of the day-to-day testing cycle: run the automated tests on the Swift codebase, translate the codebase into Kotlin, then run the same automated tests on the Kotlin version.

Table 3 :

 3 Frequency of statement types in Gryphon's codebase.

	Amount Statement name
	2698 Variable Declaration
	2168 Expression Statement
	1795 Comment Statement
	1378 Return Statement
	1120 If Statement
	831 Assignment Statement
	697 Function Declaration
	143 Class Declaration
	107 For Each Statement
	79 Initializer Declaration
	40 Continue Statement
	31 Throw Statement
	30 While Statement
	27 Break Statement
	23 Struct Declaration
	20 Do Statement
	20 Catch Statement
	18 Companion Object
	15 Switch Statement
	12 Defer Statement
	12 Import Declaration
	5 Enum Declaration
	1 Protocol Declaration
	1

Table 4 :

 4 Frequency of expression types in Gryphon's codebase.If Statement: encompasses several variations of an if statement in Swift, including common ifs and elses; if lets and if case lets; and guards. In particular, if lets may be translated as multiple statements in Kotlin, given the need to declare the variables before testing them.Throw, Do and Catch Statements: exception handling in Swift is performed in a similar manner to Kotlin. Notably, Kotlin is more permissive in its syntax and does not require users to annotate functions declarations with throws or individual calls to these functions with try. This means that many of Swift's exception annotations can be omitted in Kotlin while maintaining the same semantics.reference. These wrappers leverage Swift's metaprogramming capabilities to provide exactly the same API as the collections they wrap, making them more user friendly.Switch Statement: Swift's switch statements are translated into when statements, which can be used as expressions in Kotlin. This enables Gryphon to translate some switch statements idiomatically -for instance, when returning a value from a function: Roughly corresponds to when a variable or instance of any type is referenced, hence its high frequency in table 4.

	Amount Expression name
	17106 Declaration Reference Expression
	4592 Dot Expression
	4268 Call Expression
	3457 Tuple Expression
	3436 Literal String Expression
	2647 Binary Operator Expression
	2022 Type Expression
	1712 Template Expression
	1341 Literal Int Expression
	900 Nil Literal Expression
	830 Tuple Shuffle Expression
	687 Array Expression
	452 Literal Bool Expression
	339 Interpolated String Literal Expression
	276 Closure Expression
	235 Subscript Expression
	166 Literal Code Expression
	148 Prefix Unary Expression
	137 Literal Character Expression
	119 Optional Expression
	85 Dictionary Expression
	63 Force Value Expression
	61 Parentheses Expression
	47 If Expression
	Comment Statement: a "fake" statement created to contain a
	source comment.
	// Swift
	if let userName = networkResult {
	// ...
	}
	// Kotlin (Gryphon translation)
	val userName: String? = networkResult
	if (userName != null) {
	// ...
	}

Table 5 :

 5 Swift benchmarks run times. Times are in seconds, as an average of 600 executions. Slowdowns represent how much slower (or faster, if negative) the Gryphon version is.

	Benchmark	Hand-written Gryphon Slowdown
	Binary trees	3.55	3.53	0.56%
	Fannkuch	9.18	9.14	0.43%
	Mandelbrot	3.77	3.78	-0.39%
	NBody	3.99	3.99	-0.07%
	Spectral norm	2.88	2.87	0.55%

Table 6 :

 6 Kotlin benchmarks run times, analogous to table 5. Kotlin translation. Comparing the hand-written versions with the Gryphon versions enabled an analysis of Gryphon's impact on performance.

	Benchmark	Hand-written Gryphon Slowdown
	Binary trees	3.94	3.94	-0.14%
	Fannkuch	2.30	2.27	1.27%
	Mandelbrot	4.38	4.36	0.24%
	NBody	5.76	5.65	1.94%
	Spectral norm	7.85	7.62	3.01%
	its

There are three methods with 5 lines that are exceptions to this rule. These methods are used to implement covariant casts for the data structures: they check if the casted element types are compatible subtypes, and return either the successfully casted type or nil accordingly.

Kotlin does have access to Java's CopyOnWriteArrayList, but that class implements a different algorithm than Swift and is meant for specific use cases, as specified in its documentation[START_REF]Java SE 12 & JDK 12 Documentation: CopyOnWriteArrayList[END_REF].

ACKNOWLEDGMENTS

This study was financed in part by the Coordenação de Aperfeiçoamento de Pessoal de Nível Superior -Brasil (CAPES) -Finance Code 001

println(top-level) } Enum and Struct Declarations: Swift's structs are translated as Kotlin's data classes; common enums are translated as enum classes; and enums with associated values are translated as sealed classes. Each of these translations has similar meanings and behaviors, but they differ in their semantics -while Swift's types are passed by value, Kotlin's types are passed by reference. This difference can cause differences in behavior when the types are mutable, which can lead to bugs. Gryphon tries to avoid these bugs raising warnings when developers declare mutable members on structs and enums. The warnings can also be silenced, allowing developers to proceed once they are aware of the risks. This problem is inevitable given the semantics of the two languages, but it might be avoided with different language combinations. Array and Dictionary expressions: Similarly, Swift's Array and Dictionary collections are passed by value, while Kotlin's corresponding Lists and Maps are passed by reference. The initial attempt to solve this problem involved recreating Swift's behavior in Kotlin: if the collections were copied every time a new reference was created, the behavior would be consistent. However, this approach could significantly hurt performance.

Swift leverages its automatic reference counting mechanism to implement a copy-on-write optimization: collections are only copied when they are about to me mutated and the language knows that more than one reference is pointing to the collection; otherwise, Swift only copies the reference to the collection. Kotlin uses a garbage collector instead of automatic reference counting, meaning it does not have the necessary information on the amount of references to make the same optimization 2 . Because of this, Gryphon takes the opposite approach: it mimics Kotlin's behavior in Swift by providing wrappers to Swift's collections that are passed by the main basis for Gryphon's development). It is worth remarking that the intent here is not to criticize J2ObjC, which has been a valuable part of the mobile development ecosystem, but to highlight a specific contribution made in this work.

Consider the definition of an empty class called Hello. Xcode, the main development environment for iOS projects, creates two Objective-C files, one for the implementation and one for the interface (lightly edited below).

// Objective-C interface (Xcode template) NS_ASSUME_NONNULL_BEGIN @interface Hello : NSObject @end NS_ASSUME_NONNULL_END // Objective-C implementation (Xcode template) #import "Hello.h" @implementation Hello @end Similarly, we could define an empty Hello class in Java as follows: Similarly, J2ObjC requires users to link their iOS apps against a reimplementation of Java's standard library in Objective-C; comparatively, Gryphon requires two files that together total just over 700 source lines of code.

CONCLUSIONS

This work proposed an approach to creating a mobile development tool that avoids the dependency and integration issues as detailed. The proposed approach involves creating a transpiler that produces readable output code, depends on maintainable libraries, and provides seamless integration between shared code and native code.

The viability of implementing this approach was tested with a proof-of-concept transpiler, which was then compared with J2ObjC


Frédéric Marin

Gilles Luquet

Fre´de´ric Marin

Unusually acidic proteins in biomineralization

Keywords: acidic protein, amorphous calcium carbonate (ACC), aragonite, aspartic acid, calcite, calcium carbonate, glutamic acid, organic matrix, posttranslational modification. 16.1 Introduction: Unusually Acidic Proteins and the History of their Discovery

In the biosphere, eukaryotes represent major contributors to the production of calcium carbonate biominerals. These biominerals play a pivotal role, for several reasons [1]: (i) they are a major actor in the carbonate cycle; (ii) they represent a major sink for both calcium and carbon, and thus, participate in the climate regulation; and (iii) they contribute to maintain the Earth's homeostasis by buffering the oceans and maintaining them at a reasonable degree of supersaturation.

All calcium carbonate biominerals produced by eukaryotes share a remarkable property. They are all organo-mineral composites, where the organic phase represents only a small fraction (from <0.1 wt% to few wt%) of the total biomineral. Today, it is known that this matrix plays essential functions in mineralization [START_REF]Biomineralization, Cell biology and Mineral Deposition[END_REF]. In particular, it acts as a template for calcium carbonate deposition, by favoring the growth of calcium carbonate crystals in privileged directions, and then stopping their growth. The biomineral also stabilizes unstable or metastable polymorphs of calcium carbonate (vaterite, aragonite, amorphous calcium carbonate). In addition to these physico-chemical functions, the organic matrix may also be involved in cell-matrix interactions and cell-cell communication. This organic matrix is not homogeneous, but rather is composed of a mixture of different macromolecular components, including proteins, saccharides, glycans, and lipids.

Among the proteinaceous moiety, the key components of the matrix are the unusually acidic proteins. These are central to classical hypotheses on biomineralization, because they are always associated with calcium carbonate biominerals, and because they are shown to interact strongly with them [START_REF]On Biomineralization[END_REF].

The concept that eukaryote calcium carbonate biominerals are organo-mineral composites has long been known. In fact, such reports extend back to the mid-19th century, when Fre ´my [START_REF] Fre ´my | [END_REF] analyzed for the first time conchiolin, the insoluble organic residue of mother-of-pearl. The finding of unusually acidic proteins associated with calcium carbonate biominerals is much more recent, however. It is difficult to determine with precision who was the first to claim that acidic macromolecules were needed to bind calcium ions and nucleate calcium carbonate. The proposal was first made during the early 1960s, and formulated successively by Glimcher [START_REF] Glimcher | Calcification in Biological Systems[END_REF], Hare [START_REF] Hare | [END_REF], Simkiss [7], and Degens and co-workers [8]. [START_REF] Hare | [END_REF], had a surprisingly modern view: ''. . . the role of the organic matrix in mineralization is probably to provide a set of highly specific templates which act as the sites for the nucleation of the mineral phase . . . Aspartic and glutamic acid side chains could provide negatively charged sites, which would attract calcium ions.'' In 1967, Degens also said: ''. . . the most essential factor in nucleating a mineral phase appears to be the availability of free carboxyl groups provided by certain acidic amino acids . . .''. What appears however certain was that the detection of acidic proteinaceous fractions associated with calcium carbonate biominerals was correlated to the development and the extensive use of amino acid analyses of protein hydrolyzates.

An important step was crossed almost simultaneously by Meenakshi and coworkers, and by Crenshaw, with the discovery of the EDTA-soluble matrix [9], extracted from molluskan shells. In both cases, this matrix appeared to be singularly enriched in aspartate residues, in comparison to the EDTA-insoluble matrix, which was more hydrophobic. Although Crenshaw believed that most of the aspartate residues were in their amide form, he demonstrated that the soluble matrix was intracrystalline, since it was not degraded by NaOCl-treatment of the shell powder. This meant that the soluble acidic matrix is tightly bound to the mineral phase. A few years later, Weiner and Hood, in a key report, showed that the soluble proteins of the molluskan shell matrix were truly aspartic acid-rich and that they could act as a template for crystal nucleation [10]. Consequently, these authors proposed a first model, where the binding of calcium ions is performed via the negatively charged carboxyl radicals of aspartic acids, in a hypothetical (D-Y) n sequence (where Y can be any amino acid). They explained that the atomic distance between two consecutive calcium ions in the aragonite lattice would match the distance between two consecutive negatively charged radicals of aspartic acid in such a sequence (which implies that one calcium ion is chelated by two consecutive carboxylates). Some years later, Wheeler et al. brought another missing part to the puzzle when they observed that the acidic soluble matrix had the ability to delay the in-vitro precipitation of calcium carbonate [11] -an effect which was found to be dose-dependent. At that time, it appeared that the acidic proteins of the shell played two antagonist roles in calcium carbonate biomineralization: nucleation and inhibition. These two concepts were central to the discipline for the two decades following their discovery. Nowadays, although still important, these concepts are replaced in a more dynamic perspective, as we will see in the following sections.

What Makes a Protein Unusually Acidic?

In the light of our introduction, it seems necessary first to define an unusually acidic protein. In the living world, the majority of proteins have an isoelectric point, which is either neutral or slightly acidic. The isoelectric point (pI) is the pH value at which a protein has no net electric charge. At a pH below pI, proteins carry a net positive charge, but above pI their net charge is negative. In the proteome of the bacteria Escherichia coli, more than 90% of the abundant proteins lie in an isoelectric point window of 4 to 7 [12]. Thus, those proteins which exhibit a low pI (below 4/4.5) can be considered as ''unusually acidic''. However, such a definition is restrictive, as a protein with a pI around neutrality can exhibit very acidic functional domains, compensated by basic ones.

There are two reasons for a protein for being ''unusually acidic''. First, in its primary structure, acidic amino acids dominate, and the ratio between acidic and basic residues is largely in favor of the acidic residues. Second, this protein exhibits post-translational modifications, which bring additional negative charges to the peptide core. In the first case, the acidity of a protein is generally determined by the amount of aspartic acid (Asp, or D) and glutamic acid (Glu, or E) residues in the sequence. Aspartic and glutamic acids are the two natural amino acids, which exhibit a carboxylic acid group in their side chain (aCH 2 COOH for Asp, aC 2 H 4 COOH for Glu). Their frequencies in ''standard proteins'' are 5.3% and 6.2%, respectively [13]. The other parameter to consider is the ratio between these amino acids and the sum of lysine (Lys or K), arginine (Arg, or R) and histidine (His, or H): a protein with only few D or E residues can indeed exhibit a relatively acidic pI if it contains very few basic residues. For example, this is the case for GAMP, a crustacean matrix protein (see Section 16.5.2.5, Arthropods).

Post-translational modifications represent a second way to increase the polyanionic characteristic of a protein. In the case of proteins associated with biominerals, the most frequent modifications are glycosylation, phosphorylation, sulfation, and carboxylation of glutamic acid [14]. Glycosylation is the enzymatic addition of a saccharide moiety to a protein core [START_REF] Creighton | Protein Structure: a Practical Approach[END_REF]. Two types of glycosylation exist: N-linked glycosylation to the amide nitrogen of asparagine side chain, and O-linked glycosylation to the hydroxyl group of serine or threonine side chain. The first type is found for example in the molluskan shell protein dermatopontin [START_REF] Marxen | [END_REF], whereas the second type is suspected to be the main glycosylation type of mucoperlin, another shell protein [17]. Although not all glycosylations modify the net charge of a protein, some do, such as the addition of sialic acids (a family of nine-carbon, negatively charged monosaccharides), the addition of polysaccharides composed of acidic sugars such as glucuronic acid (e.g., hyaluronic acids), or the addition of saccharides which exhibit a terminal sulfate group.

The second important post-translational modification is phosphorylation, which represents the addition of a phosphate group (PO 4 ) on to serine (the most frequent case), threonine, or, more rarely, on to tyrosine [START_REF] Creighton | Protein Structure: a Practical Approach[END_REF]. Phosphorylations are catalyzed by protein kinases, an extremely diversified family of enzymes. Phosphorylations are extremely important in biomineralization systems and fulfill important functions. Phosphate groups are thought to bind calcium ions in cooperation with carboxylic groups [18]. For example, phosphophoryn, which is found in the dentin matrix, is highly phosphorylated, and the phosphate groups are important for its function as a mediator of dentin biomineralization [19]. RP-1, a molluskan shell protein is a potent inhibitor of calcium carbonate precipitation in vitro, but this effect is completely dependent on phosphate groups, as the dephosphorylation of RP-1 results in a complete loss of any inhibitory effect [20]. Orchestin, a protein associated with calcium storage concretions in a terrestrial crustacean, is a calcium-binding protein. Here again, this ability, which is conveyed by phosphorylated serine residues, is lost when serine is dephosphorylated [21].

Another post-translational modification, which can increase the negative charge of a protein involved in biomineralization, is sulfation -that is, the addition of a sulfate group to the side chain hydroxyl group of a tyrosine residue. Several extracellular matrix proteins exhibit sulfated tyrosine residues [22]. In biomineralization research, however, this post-translational modification is poorly documented, although its existence is suspected on the basis of computer-based analyses of the primary structures of several biomineralizing proteins [23].

Finally, the carboxylation of glutamic acid residues leads to the formation of g-carboxy-glutamic acid (abbreviated as Gla). Proteins containing Gla residuessuch as osteocalcin and matrix Gla protein -are important constituents of calcium phosphate biominerals, such as bone [24]. However, to our knowledge, Gla has not yet been detected in proteins associated with calcium carbonate biominerals.

Biochemical Techniques for Studying Unusually Acidic Proteins

Because unusually acidic proteins are strongly bound to the mineral phase, they are usually released by dissolving the calcium carbonate powder, with concentrated EDTA (directly in solution or by dialysis against EDTA) [10, 25], with dilute acetic acid [26], or more rarely with hydrochloric acid [27] or formic acid [28]. EDTA functions at neutral pH and therefore, does not denature matrix proteins. On the other hand, EDTA forms aggregates which are difficult to remove, even by extensive dialysis [29]. Thus, when not completely removed, EDTA can dramatically interfere with subsequent investigations such as inhibition tests or the invitro growth of calcite. In this regard, our preference is to use dilute (5% v/v) cold (4 C) acetic acid, which is progressively added to the decalcifying solution using an automatic titrimeter, such that the pH never falls below 4. Another interesting possibility is the soft demineralization of calcium carbonate powder on a cation-exchange resin [30]. Extraction of the matrix with bi-distilled water, as has been performed in few cases [31], is insufficient to extract acidic proteins.

Once solubilized, the acidic proteins, which are considered to be major components of the matrix soluble fraction [10], are then separated from the insoluble fraction by centrifugation. They are subsequently concentrated and purified from the mineral ions, by combining ultrafiltration and dialysis. When they are free from salts, they can be analyzed by using different biochemical methods, in order to obtain structural information. Usually, because these proteins do not have a globular shape, gel permeation chromatography is not very effective in resolving discrete molecules. To date, the most relevant fractionation techniques have been a combination of high-performance liquid chromatography (HPLC) and ionexchange chromatography [32], or polyacrylamide gel electrophoresis under denaturing conditions (SDS-PAGE) [33]. Even by optimizing the fractionation conditions, unusually acidic proteins have a tendency to smear, except when extracted from amorphous calcium carbonate (ACC) structures [34] or from eggshells [35].

The analysis of acidic proteins by gel electrophoresis requires some precautions to be taken. First, denaturing conditions must be used [36] in order entirely to dissociate the macromolecular complexes formed in the matrix. Second, acidic proteins do not stain easily with Coomassie Brilliant Blue (CBB), because they are often poor in, and sometimes devoid of, any aromatic and basic amino acids, with which the anionic blue form of CBB reacts exclusively [37]. Classical silver staining can be employed [38], although despite the high sensitivity of this staining, ''negative staining'' patterns of acidic proteins are often observed [19a]. Furthermore, because of their charge, acidic proteins tend to diffuse quickly out of the gel. This obstacle can be precluded by a double fixation of the gel after the electrophoresis, and a modification of the staining procedure, which visualizes all of the acidic macromolecules [39]. Other staining procedures can be used for visualizing highly acidic proteins, in particular Alcian blue [40] or carbocyanine (Stains-all) [41]. Alcian blue stains blue the polyanionic macromolecules (proteins, glycoproteins, proteoglycans, acidic polysaccharides), and seems adapted for acidic proteins, but is not very sensitive. Carbocyanine dye stains blue the polyanionic proteins (e.g., sialoglycoproteins, phosphoproteins, calcium-binding proteins), and the other proteins red. One peculiarity of the Stains-all staining is that calcium-binding proteins exhibit generally a distinctive metachromatic blue color [21,42]. However, in some cases, polyanionic molecules such as calciumbinding proteins stains purple with carbocyanine [42]. Our own experience has shown that some unusually acidic proteins of the shell of the bivalve Pinna nobilis stains also purple with carbocyanine [43]. However, this staining is not very sensitive and fades rapidly when exposed to light. Modifications have been performed for improving the sensitivity and stability of carbocyanine staining by combining Stains-all and silver staining [44]. In addition to carbocyanine, red ruthenium, which initially is used as a histochemical dye for acidic glycosaminoglycans, specifically stains red any calcium-binding proteins [45], and may consequently be used to detect such proteins among matrix acidic components.

One peculiarity observed for highly acidic proteins is their behavior in SDS-PAGE: they migrate to a calculated molecular mass higher than their molecular mass deduced from their sequence or evaluated by mass spectrometry. This is the case for nacrein, a molluskan shell protein (see Section 16.5.2.6), and for GAMP and orchestin (two crustacean calcium storage structures proteins; see Section 16.5.2.5). If this discrepancy can be attributed to the putative presence of posttranslational modifications, then another explanation lies in the presence of strongly biased amino acid domains which are known to bind SDS poorly [46]. Among these domains are those rich in acidic amino acids (e.g., asp-rich).

Following electrophoresis, unusually acidic proteins can be blotted onto nitrocellulose membranes, and studied for their ability to bind radioactive calcium ions [47]. This test has been applied successfully in a number of cases [21,48], although some acidic proteins associated with calcium carbonate biominerals do not bind at all (because they are unable to renature during electro-transfer on the membrane [49]), or they bind calcium very poorly. The calcium overlay test developed by Ebashi and co-workers was primarily adapted to high-affinity-lowcapacity calcium-binding proteins -that is, proteins with canonical calciumbinding domains, such as EF-hand [50]. Several extracellular calcium-binding proteins do not exhibit EF-hand motifs or other canonical calcium-binding domains, and bind calcium only with a low affinity [51]. Because unusually acidic proteins associated with calcium carbonate biominerals exhibit domains rich in glutamate or aspartate when they are calcium-binding, chelation of the calcium ions (sometimes in cooperation with other anionic groups such as phosphate or sulfate) is performed with a high capacity and a low affinity. This type of affinity is compatible with the nucleation process, which requires a reversible binding of calcium ions [52]. Our own practical experience has shown that the Maruyama test must be adapted in some cases, for such proteins, for example by reducing the time for rinsing the membranes, and by increasing the time of film exposure.

Other characterizations of unusually acidic proteins blotted onto nitrocellulose membranes include studies of their putative post-translational modifications. For example, phosphorylations can be studied with commercially available antibodies raised against phosphoserine, phosphotyrosine or phosphothreonine, or by performing either a complete (e.g., by using the lambda protein phosphatase) or specific (using Ser/Thr-or Tyr-protein phosphatase) enzymatic cleavage. Another approach consists -after in-vivo labeling of phosphoproteins with radioactive phosphate -of identifying the labeled amino acids. Following the in-vivo injection of 32 Pi, the whole organic matrix proteins are classically extracted, then submitted to an acidic hydrolysis followed by a separation by thin-layer chromatography. The radiolabeled amino acids were revealed by autoradiography and identified by comparison with standard phosphoamino acids [21].

Glycosylation studies can be approached via analysis with lectins (carbohydratebinding proteins), via chemical treatment using trimethanesulfonic acid (TMFS) followed by a high-performance anion-exchange chromatography, or via enzymatic deglycosylations (with a mixture of glycosidases or with single specific glycosidases) [43].

During the past 20 years, few functional tests have been developed for monitoring the effect of unusually acidic proteins on the crystallization of calcium carbonate. For the in-vitro inhibition test, known amounts of an acidic protein are added to a solution of sodium bicarbonate (10 mM) to which a solution of calcium chloride is quickly added [25,[START_REF] Wheeler | Chemical Aspects of Regulation of Mineralization[END_REF]. Variations of the pH values indicate whether the spontaneous precipitation of calcium carbonate (calcite) occurs normally, or whether the process is delayed. If the latter, the delay corresponds to the inhibiting effect of the tested acidic protein. A variant of this test consists of maintaining a constant pH (the pH stat test) by adding the required volume of sodium hydroxide via an automatic titrimeter [11]. The volume added is inversely proportional to the inhibiting capacity of the tested molecule. Another semiquantitative variant of this test consists of measuring in a Petri dish the inhibition zone caused by acidic proteins on calcium chloride-containing agarose hydrogel immersed in sodium bicarbonate solution [START_REF] Boggavarapu | [END_REF]. The second test, the ''interference test'', consists of growing calcium carbonate crystals, by slow diffusion of ammonium bicarbonate vapors into a solution of calcium chloride, to which known amounts of acidic proteins are added [27]. The crystals are then observed by scanning electron microscopy. In ''blank'' tests, most of the crystals have the typical rhombohedral shape. Interfering acidic proteins can drastically modify the shape of the crystals, by provoking the development of new crystal faces, or by promoting the appearance of polycrystalline aggregates. The effect is also dose-dependent. Several acidic proteins associated with calcium carbonate biominerals are known to exert an effect at concentrations as low as 1 mgm L À1 .

Interactions of Acidic Proteins with Calcium Carbonate Crystals and Organo-Mineral Models

At nanoscale and molecular scale, the problem of the interactions of acidic proteins with calcium carbonate biominerals has been solved by a variety of comple-mentary techniques, including classical scanning electron microscopy (SEM) observations, cryo-transmission electron microscopy (TEM), X-ray diffraction, atomic force microscopy (AFM), computer-based molecular modeling, crystal growth experiments in the presence of acidic protein followed by SEM observations, circular dichroism (CD) and NMR structural analyses from synthetic peptides. Much of our knowledge has been derived from studies conducted by Weiner, Addadi, Aizenberg and co-workers [27,[START_REF] Addadi | Proc. Natl. Acad. Sci[END_REF], the group of Stephen Mann [56], Wierzbicki, Sikes and co-workers [57], the group of De Yoreo [58], DeOliveira and Laursen [59], the group of John Evans [60], and Valiyaveettil and coworkers [61]. In a number of studies, the molluskan shell or sea urchin spines were used as a model system. Briefly, different modes of interactions of unusually acidic macromolecules with calcium carbonate crystals can be distinguished. Acidic proteins can induce nucleation, adsorb specifically onto some crystal faces, and/or intercalate in a controlled manner into the crystal lattice. It has also been suggested that, in some cases, they stabilize amorphous calcium carbonate.

As noted above, the consecutive discoveries of Weiner and Hood, [10] and of Wheeler and co-workers [11], led to the idea that acidic proteins play two antagonistic roles, depending on their state. Thus, when adsorbed onto an organic insoluble template, the acidic proteins promote crystal nucleation, but when they are free in solution they play an opposite role, by inhibiting crystal growth. In the initial nucleation model of Weiner et al. [62], which was developed from molluskan shell biomineralization, the acidic (Asp-rich) proteins were bound to a ''sole'' of hydrophobic silk-fibroin-like proteins (adopting the antiparallel b-sheet conformation). These insoluble proteins were in turn attached to a chitin core. In this ''sandwich'' model, the carboxylate functions of the side chains of aspartic acid residues were accessible to calcium ions. Sulfated polysaccharides, which supposedly were bound to the acidic protein core, could also contribute by attracting and concentrating calcium in the vicinity of the soluble template [55a]. The crystals then could grow on top of the polyanionic layer. As described, the model was related to hetero-epitaxy.

The initial molluskan biomineralization model presented above has undergone drastic evolution during the past few years, for two reasons. First, recent cryo-TEM observations of nacre samples have brought to light a completely different organization of organo-mineral assembly [63]. Second, very recently Co ¨lfen and co-workers discovered that each nacre tablet in the nacreous shell layer of Haliotis laevigata is surrounded by a thin layer of ACC [START_REF] Nassif | Proc. Natl. Acad. Sci[END_REF]. With regard to the first aspect, Levi-Kalisman and co-workers proposed a molluskan nacre model where b-chitin provides the insoluble organic framework, in which the hydrophobic (Gly/Alarich) proteins (the silk-fibroin-like proteins) form a gel. The acidic proteins are thought to be clustered at the interface between the framework and the gel, and also to be entrapped within the gel. Aragonite tablets nucleate within the gel, and push away the gel by expanding their size. The second aspect concerns the formation of transient amorphous calcium carbonate. The fact that the elaboration of any crystalline calcium carbonate biomineral (calcite or aragonite) could be pre-ceded by a preliminary step, during which ACC forms, seems to be a general phenomenon which is shared by mollusks, crustaceans, and echinoderms [65]. This reconstitutes the role of acidic proteins in a more general context, where they cooperate with other components of the matrix, in a highly controlled sequence [66]. First, the framework (chitin) is built, after which the initial mineral granules (ACC) are secreted (they may be formed intracellularly and exported to the site of crystallization). The role of acidic proteins, at this stage, remains obscure: it is unclear whether they stabilize the ACC for a short period, during the transit of amorphous precursor granules from the cell to the site of mineralization, or whether they provide the inhibiting micro-environment between the secreting cells and the location of mineral assembling process. The third stage is nucleation of the crystals (aragonite tablets), driven by acidic proteins, in cooperation with sulfate groups. The final stage is growth of the formed crystals, and completion of the mineralizing cycle.

Because acidic proteins exhibit several anionic sites, they can interact strongly with calcium carbonate crystals. The crystal-binding properties imply that there is a molecular recognition between acidic proteins and the mineral surfaces. This recognition involves both the primary (Asp-rich domains) and the secondary structure (b-sheet) of acidic proteins. In numerous cases, it has been shown that negatively charged polypeptides (e.g., poly-aspartic acid) are extremely effective inhibitors of calcium carbonate growth [START_REF] Sikes | Surface Reactive Peptides and Polymers: Discovery and Commercialization[END_REF], as they are much more potent inhibitors than small mineral ions (Mg) or small organic molecules such as free aspartic acid. Their effect is reinforced when they are associated with a hydrophobic domain [START_REF] Sikes | Surface Reactive Peptides and Polymers: Discovery and Commercialization[END_REF]. One mechanism involved is that they are adsorbed onto crystal nuclei, and ''poison'' them. When the acidic proteins cover all the faces of small growing nuclei, the crystals can no longer grow and the inhibition is complete. When acidic proteins are adsorbed onto specific faces, the crystals grow in privileged directions [55a] and the final crystal shapes are different from those of calcium carbonate crystals, and synthesized in a purely chemical manner.

The controlled intercalation of acidic proteins into the crystal lattice of calcite or aragonite serves as a general mechanism, and explains, for example, why the sea urchin calcitic spine has a better resistance to fracture than pure calcite. In particular, the spine does not break along the [104] plane of calcite, which is the most frequent cleavage plane. The intercalation of acidic glycoproteins along crystal planes that are oblique to the [104] plane modifies the mechanical properties of the spine. Consequently, this latter crystallographic plane is not privileged when mechanical constraints are applied. The intercalation is controlled and differential, according to the type of acidic proteins. This has been demonstrated in two cases. First, partly purified proteins from the spines of the sea urchin Paracentrotus lividus were found to interact only with faces roughly parallel to the c crystallographic axis of calcite. Second, the soluble matrix of the calcitic prisms of Atrina rigida, a bivalve, can be divided in two populations of proteins: the most acidic interacting with the {001} set of faces, and the less acidic, with the {01l} set of faces [27, 55h]. Computer simulations and AFM observations performed with synthetic poly-Asp peptides show that they bind {110} faces of calcite, and that they stretch in parallel rows in a direction parallel to the c crystallographic axis [START_REF] Sikes | [END_REF].

Recently, another effect of acidic proteins in calcite biominerals was detected. Pokroy and co-workers [69], by measuring the lattice parameters of different biogenic molluskan calcite biominerals, observed a slight lattice distortion (about 2 Â 10 À3 ), after taking into account the required corrections for magnesium and sulfur. This distortion is not isotropic, but rather is maximal along the c axis. It was further demonstrated that calcite crystals grown in the presence of one acidic protein, caspartin, exhibit a similar lattice distortion. Although this effect can only be measured with an extremely precise X-ray diffractometer, it is clearly significant.

Occurrence of Unusually Acidic Proteins in Selected Metazoan CaCO 3 -Mineralizing Phyla

So far, unusually acidic proteins are a feature seen to be shared by most -if not all -calcium carbonate-mineralizing phyla. However, it must be borne in mind that for some eukaryotic phyla, our knowledge is extremely limited: for example, we know virtually nothing of the molecular aspects of the biomineralization of the bryozoans, a group of colonial animals that, in geological times, has had considerable importance as reef-builders. The situation is similar for several calcifying green or red algae. In contrast, a wealth of data is becoming available for mollusks, crustaceans, echinoderms, or vertebrates. In between these situations, the foraminifera, calcifying sponges, brachiopods, urochordates (tunicates) have also been studied, though much of our knowledge is based on a limited number of amino acid compositions of bulk matrices or, in the best cases, the amino acid compositions of purified proteins. Cnidarians represent a phylum for which several amino acid compositions of bulk skeletal matrices were determined during the 1970s and 1980s, and for which sequence data on skeletal proteins have just begun to be published.

Here, we have deliberately chosen to assemble the data on unusually acidic proteins characterized from three different mineralizing systems, for which several protein sequences have been published and are available in protein databases, into three tables. These comprise the molluskan shell (Table 16.1), the cuticle and calcium storage structures of crustaceans (Table 16.2), and finally, the eggshell (Table 16.3). We selected only those proteins which exhibit a theoretical pI below 6. For mollusks, approximately 22 protein sequences are known, of which 14 are acidic and four can be considered as extremely acidic (pI < 4). For crustaceans, 28 complete cuticular protein sequences (plus nine partial sequences) have been retrieved. In addition, two complete protein sequences of calcium storage structures have been determined. From these 30 sequences, 21 can be considered The pI and D þ E percentage values are calculated from each protein primary sequence, devoid of the signal peptide when predictable, obtained in the Swiss-Prot/TrEMBL database. This does not take into account the putative post-translational modifications, which could occur in vivo and modify the pI of the mature proteins. Only completely sequenced proteins, the pI of which is <6, have been listed. These were retrieved from bivalves (BIVALVIA) and gastropods (GAS).

as unusually acidic and are consequently presented in Table 16.2. For the eggshell, 17 sequences are known, but only nine are acidic. There is no doubt that, in the near future, these three lists will be considerably extended, in particular because several genome sequencing projects are currently under way (see www.genomesonline.org), and will soon provide a wealth of information on the organization (introns and exons) and of the location of each calcifying gene. This is already the case for the sea urchin Strongylocentrotus purpuratus, for the edible mussel Mytilus californianus, and the lobster Homarus americanus. The pI and D þ E percentage values are calculated from each protein primary sequence, devoid of the signal peptide when predictable, obtained in the Swiss-Prot/TrEMBL database. This does not take into account the putative post-translational modifications, which could occur in vivo and modify the pI of the mature proteins. Only completely sequenced proteins, the pI of which is <6, have been listed. These are essentially components of the cuticle matrix, except for the final two from calcium storage structures.

Concluding Remarks

The review on unusually acidic proteins involved in biomineralization calls for few remarks.

First, most of our present knowledge is restricted to a limited number of species, namely two coccolithophorid algae, a few foraminifera, four cnidarians, eight mollusks (four bivalve species, four gastropod species), seven arthropods, and five echinoderms. The question thus remains as to whether this sampling is sufficient to provide a good representation of the acidic proteins associated with calcium carbonate biominerals. The answer is, probably not, considering the huge size of some phyla (mollusks and arthropods) and the diversity of skeletal textures (corals and mollusks). Most likely, we have a very partial view of the diversity of all unusually acidic proteins involved in biomineralization, and are just ''discovering the tip of the iceberg''.

Second, the acidity of unusually acidic proteins is often due to aspartic acid, rather than to glutamic acid. Although there are several exceptions to this (e.g., some crustacean proteins), there is a net tendency for biological systems to choose aspartic acid -a remarkable selection which to date is totally unexplained. The pI and D þ E percentage values are calculated from each protein primary sequence, devoid of the signal peptide when predictable, obtained in the Swiss-Prot/TrEMBL database. This does not take into account the putative post-translational modifications, which could occur in vivo and modify the pI of the mature proteins. Only completely sequenced proteins, the pI of which is <6, have been listed. All protein sequences were obtained from avian species (except pelovaterin, from a turtle).

Third, all of the known skeletal proteins are not acidic when considering their primary structure. For example, in the case of mollusks about one-fifth of the proteins are unusually acidic, while the remainder are acidic, neutral, or even basic. This is even more striking in the case of sea urchins, where most of the spicule proteins exhibit a (theoretical) neutral or basic pI. One aspect to consider is, of course, post-translational modifications, that can drastically modify the properties of biomineralization-associated proteins, and increase their polyanionic properties.

Fourth, most of the unusually acidic proteins belong to the soluble fraction. However, some limit-cases exist, such as the molluskan shell protein MSI31 [73], or the crustacean GAMP [87]. For example, MSI31 exhibits hydrophobic domains typical of framework insoluble proteins, in addition to acidic domains, which are characteristic of soluble shell proteins. GAMP is an insoluble protein, rich in glutamine residues (20%), with an acidic pI (4.11) and glutamic acid residues (9%) dispersed throughout its N-terminal half. These counter-examples make the classic dichotomy between acidic soluble proteins and hydrophobic insoluble proteins less pertinent.

Which brings us to the final remark. Many of the unusually acidic proteins and, more generally, of proteins associated with calcium carbonate biominerals, are modular, with each module corresponding to a functional domain. As a consequence, most of these proteins must be multifunctional, though how they function is still beyond our comprehension. Clearly, a major effort must be made to understand the function(s) of these proteins, and in that sense the morpholino approach, as used in the otolith system [95], may provide some promising results.

Table 16 . 1

 161 Acidic proteins from mollusk shell organic matrix.

Table 16 . 2

 162 Acidic proteins from crustacean organic matrix.

	Protein name	Species	Origin	pI	D [%] E [%] Swiss-Prot/	Reference
							TrEMBL
							accession
							number
	HaCP4.4	Homarus americanus Cuticle	5.88	2.2	0	Q7M494	81
	HaCP4.6a, b	""	4.68	6.7	2.2	Q7M4A1, A2 81
	HaCP9.3	""	5.44	2.4	4.7	Q7M491	81
	HaCP11.6a	""	5.86	0.9	3.6	Q7M4E3	81
	CpCP4.59	Cancer pagurus	Cuticle	4.59	2.3	9.1	P81586	82
	CpCP4.66	""	4.94	4.5	6.8	P81590	82
	CpCP4.98	""	4.83	2	6	P81588	82
	CpCP5.75	""	4.05 13.7	11.8	P81589	82
	CpCP/AMP11.14	""	4.22 12.7	4.9	P81575	82
	CpCP12.43	""	4.65	7.7	5.1	P81581	82
	CpCP12.46	""	4.36	9.4	5.1	P81582	82
	CsCP8.2	Callinectes sapidus	Cuticle	3.78 18	7.9	Q5XLJ9	83
	CsCP8.5	""	4.01 17.2	6.9	Q5XLK0	83
	CAP-1	Procambarus clarkii	Cuticle	3.83 20	8.8	Q7YUE2	84
	CAP-2	""	3.98 10.8	18.5	Q75PH3	85
	DD4/Crustocalcin Penaeus japonicus	Cuticle	3.84	5.3	15.6	Q9GUY4	86
	DD5	""	5.33	7.3	3.8	Q9GUY5	86
	DD9A	""	4.09	8.8	11.5	Q9NDS2	86
	DD9B	""	4.15	9.7	10.6	Q9NDS3	86
	GAMP	Procambarus clarkii	Gastroliths	4.11	1.6	9	Q9U913	87
	Orchestin	Orchestia cavimana	Concretions 4.4	16.7	13	Q9XYT4	88

Table 16 . 3

 163 Acidic proteins from eggshell organic matrix.

	Protein name	Origin	pI	D [%] E [%] Swiss-Prot/	Reference
						TrEMBL
						accession
						number
	Osteopontin	Gallus gallus	4.53 12.9	9.3	P23498	89
	Clusterin	"	5.48	5.9	10.1	Q9YGP0	90
	Serum albumin	"	5.46	6.9	8.4	P19121	90
	Ovalbumin	"	5.2	3.6	8.6	P01012	91
	Ovocalyxin-36	"	5.38	4.3	3.0	Q53HW8	92
	Struthiocalcin-2 Struthio camelus	5.41	6.3	10.6	P83515	93
	Rheacalcin-2	Rhea americanus	4.85	6.3	12.6	P84618	93
	Dromiocalcin-2 Dromaius novaehollandiae 4.87	7	9.9	P84616	93
	Pelovaterin	Pelodiscus sinensis	5.3	7.1	0	P84818	94