Java → C# translation: an idiomatic C# printer driven by the modification and nullability analyses
Nobody has claimed this yet.
Assessment
- Difficulty
- 5/5
- Estimated time
- Over a week
- Newbie friendliness
- 8/100
Research direction
Start by reading the Kotlin printer, maddi-cst-print-kotlin, and its JavaToKotlinRatchet, KotlinPrintMessage and NullabilityVerdicts seam, since the issue says the C# printer mirrors them. The first step is the new maddi-cst-print-csharp module with its TypePrinter/MethodPrinter/FieldPrinter implementations and a csharp-printing.md design doc. The issue does not define a finished state beyond the six-step plan, so a newcomer should not start here.
Written by the indexing model from the issue text.
Description
Goal
Translate Java to idiomatic C#, automatically: parse with the openjdk front end, print the CST as C# with a new maddi-cst-print-csharp module, and judge the result with the C# compiler. This is the C# counterpart of the Java → Kotlin translation (maddi-cst-print-kotlin, JavaToKotlinRatchet).
This is the printer direction. #111 covers the opposite direction (a Roslyn front end reading C#) and lists a C# printer as out of scope. Nothing here depends on #111's plan: the struct spike, the Predefined refactor and the exporter are front-end work. A Java-parsed CST is JVM-shaped, and the printer starts from that.
What drives it: the analyses
What sets this apart from a syntax converter is that maddi's analyses decide the output:
- Nullability (
NullabilityPassin maddi-mod) decides where?goes on reference types under#nullable enable, and where!,?.or??appear. TheNullabilityVerdictsseam thatmaddi-cst-print-kotlinuses carries over directly. - Modification and immutability decide whether something can be
readonly,init-only orIReadOnlyList<T>/IReadOnlyDictionary<K,V>, whether a class can become arecord, and whether a value type (readonly struct) is safe. Where the analysis proves code doesn't modify something, the C# says so. - Prepwork (
getSetField) collapses getters and setters into C# properties, as it does for Kotlin.
Without verdicts the printer still produces valid C#, just less precise: every reference is nullable-oblivious and every collection mutable.
Automation
The translation has to run without manual editing. It is measured the way J2K is: a ratchet per corpus (fernflower first) that translates the main sources, compiles them with dotnet build / Roslyn, and records syntax errors, semantic errors, compiling files and eventually passing tests. A metric that gets worse fails, and one that gets better must be written into the ratchet file. A shape the printer can't translate gets a named message (as KotlinPrintMessage does), never silently wrong output.
Harder than Kotlin
- No JVM interop. Kotlin can call the JDK and the corpus's original classes; C# can't. JDK references need a BCL mapping or a small runtime shim (
java.util.*,Stringmembers, streams → LINQ, exceptions, boxing). This mapping is the bulk of the work. It also means there is no "compile against the original classes" stage: the whole corpus has to translate first. - Semantic gaps:
- checked exceptions are dropped;
- wildcards (
? extends/? super) on reified generics; - non-static inner classes need an explicit outer reference;
- anonymous classes become nested classes, or lambdas/delegates for functional interfaces;
- enums with fields or bodies become classes;
- Java methods are virtual by default, so C# needs
virtual/override/sealed; >>>, integer andcharconversions, stringswitch, labelledbreak/continue(→goto).
Plan
maddi-cst-print-csharp: printers on the cst-apiTypePrinter/MethodPrinter/FieldPrinterinterfaces, reusingOutputElementandFormatter2; aCommonJavaToCSharptest base; acsharp-printing.mddesign document.- Syntax coverage of every statement and expression form, plus a
JavaToCSharpRatcheton fernflower counting syntax errors. - Structure and the JDK → BCL mapping: semantic errors, then compiling files.
- Nullability verdicts →
#nullable enableoutput, with a ratchet in maddi-mod (likeTestJavaToKotlinFernflowerNullability). - Modification/immutability verdicts →
readonly, read-only collection interfaces, records. - The corpus's tests, translated, passing.
- Dominant language
- Java
- Stars
- 1
- Forks
- 1
- Avg merge
- 2h 51m
- Merged PRs (30d)
- 3
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from CodeLaser/maddi
-
build/ci good first issue
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
-
enhancement
Difficulty 3/5 1-2 days Newbie friendliness 45/100
-
bug
Difficulty 4/5 3-5 days Newbie friendliness 40/100
-
bug
Difficulty 4/5 3-5 days Newbie friendliness 45/100
-
bug
Difficulty 3/5 1-2 days Newbie friendliness 45/100
Similar issues
-
[BUG] 订单:会员凭订单号即可取消其他会员的待付款订单(取消接口不校验订单归属)Possibly taken @dadiyang claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
macrozheng/mall#1016 ·
-
[Bug] The producer summary counts an unreported client version as a second version and warns about a version mixPossibly taken A pull request linked to this issue is open or already merged. Open
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
apache/rocketmq-dashboard#6110 ·
Maintainers usually reply within 4 days
-
Feature:Resolution
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
intellij-elixir/intellij-elixir#4396 ·
Maintainers usually reply within 1 day
-
Python 3.15 supportPossibly taken @amnesiaof claimed this today. OpenL: python L: python:uv
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
dependabot/dependabot-core#16524 · 1 comment ·
Maintainers usually reply within 1 day
-
`Processing lsp` never exits and leaves orphaned processesPossibly taken @overcast302 claimed this today. Openbug
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
processing/processing4#1578 · 1 comment ·