Skip to content

Comparison With Other Languages

gnumonik edited this page Jan 24, 2025 · 2 revisions

Why not PlutusTx?

PlutusTx employs the TemplateHaskell language extension to enable users to write vanilla Haskell code that compiles down to UPLC. On paper, this appears to be an excellent solution. The Haskell development ecosystem contains excellent tooling (mature build systems, a reliable language server that integrates with every mainstream editor/IDE, etc). Moreover, GHC is capable of performing remarkable optimizations when compiling Haskell programs, which presumably could be leveraged to generate efficient and compact UPLC.

Unfortunately, PlutusTx falls woefully short in practice. Most importantly, the UPLC emitted by PlutusTx is, in almost every case we are familiar with, significantly inefficient in terms of both script size and execution speed. While PlutusTx may be suitable for extremely simple scripts, we do not consider it to be a viable option for complex projects. Choosing PlutusTx for a complex project is just too risky - it may turn out that the design for a complex smart contract cannot possibly be implemented in PlutusTx without exceeding script size limits. Even if the script size can be minimized, execution performance is often so poor with PlutusTx that the resulting fees render a contract's protocol economically unviable. These are not merely theoretical objections; several members of our team have been involved in PlutusTx projects which ultimately required complete rewrites in Plutarch - at great expense to clients. We note that some of these projects ultimately failed due to the increased expense of a ground-up rewrite.

It may be possible to squeeze performance gains out of PlutusTx by performing certain optimizations in the Haskell code that serves as input to its compile functions. However, this is extremely unintuitive - a developer attempting to optimize PlutusTx is put in the incredibly awkward position where they must reason about how changes to Haskell code affect UPLC output in spite of the fact that Haskell (a lazy language) and UPLC (a strict language) have different semantics. Even if one could account for the different semantics, the machinery that performs the Haskell -> UPLC translation is an incredibly obscure TemplateHaskell. It is unreasonable to expect that even the most talented developers would be able to perform these tasks.

On a more mundane level, PlutusTx simply does not integrate well with the Haskell ecosystem's tooling. We have lost dozens - if not hundreds - of hours tracking down incredibly obscure errors emitted by the Haskell language server when using PlutusTx. Moreover, PlutusTx requires the use of a special standard library, which makes integration with existing Haskell libraries impossible and (again) gives rise to extremely confusing errors if one accidentally mixes functions from the Plutus standard library with functions from Haskell's prelude. These errors are not intractable, but solving them requires a large amount of folk-wisdom that makes it very difficult to onboard new developers and greatly increases development costs.

Why not Plutarch?

Plutarch eschews compilation-via-metaprogramming for a sophisticated embedding strategy that enables an embedded UPLC DSL. In many respects, Plutarch is a substantial improvement over Plutus: Plutarch, when used by an experienced developer, results in scripts with vastly smaller sizes and greatly improved performance compared to an equivalent PlutusTx implementation.

Although these improvements over PlutusTx have enabled more sophisticated smart contracts, the embedding strategy that powers these performance increases entails a severe cost in terms of ergonomics. At a glance, writing Plutarch requires:

Heeding the distinction between Plutarch-level and Haskell-level functions, which can be very confusing to developers who are not familiar with complex embedded DSLs
The capability to write performant "raw" Lambda calculus, which is a skill that not many developers (even experienced functional developers) possess. (To use a simple example, it is frequently necessary to use fixed-point combinators directly in Plutarch) 
A slew of conversions between different data encodings and representations, such that it is frequently unclear which representation should be used in a particular context
Familiarity with dozens of complicated types and type classes, including (but not limited to) `PLift, PLifted, PConstant, PConstanted, PIsData, PIsDataRepr, PIsDataField, PListLike, PTryFrom, PlutusType, PCon, PMatch, PAsData, PData, PDataSum, PDataRecord`. Many of these types and type classes are implemented using cutting-edge Haskell type system features and type-level programming techniques, rendering the Plutarch source code inaccessible even to experienced Haskellers
The ability to reason about complex custom deriving strategies
Coping with a large amount of syntactical noise necessitated by the embedding strategy

As type system enthusiasts, we find Plutarch to be a fascinating example of what is possible when the Haskell type system is pushed to its limits. As smart contract developers, however, our familiarity with Plutarch has made clear that it is not a viable general solution to the problem of Cardano smart contract development. The degree of niche expertise required to make full use of Plutarch is just too high.

Why not Aiken?

Aiken, a bespoke language for developing Cardano smart-contracts with a rust-like syntax, is an excellent solution for developers that do not specialize in functional programming. However, Aiken's main strength - a much simpler type system than Haskell’s combined with conventional imperative syntax - is, at the same time, a limitation: While Aiken's simplicity enables imperative developers to build on Cardano without struggling to adopt a new paradigm, it also prevents functional programmers from leveraging a strong type system to create abstractions and express sophisticated invariants at the type level. Aiken does not support type classes, data-generic programming, effects systems (monads, monad transformers, etc), or optics (functional-style data manipulation). Admittedly, these language features can be difficult to master, but when mastered they provide developers with the power to significantly simplify codebases and write intrinsically secure code. In the context of smart-contract development, the absence of these features is likely to lead to verbose code (which increases auditing costs and increases the potential for bugs) that is less secure (because certain important invariants cannot be expressed without these features).

Nevertheless, we acknowledge that Aiken is the right choice for many projects, especially those with relatively simple on-chain logic. In our experience, many projects have relatively simple on-chain logic, and would do better to choose Aiken than Purus. As functional programmers, however, we believe that the advanced features found in strongly-typed pure functional languages are sometimes the best tool for the job. Aiken, in our view, is one part of the solution to the problem of Cardano smart-contract development - but that it is only one part of the solution.

Clone this wiki locally