Skip to content

Conversation

@HT154
Copy link
Contributor

@HT154 HT154 commented Nov 25, 2025

This has been banging around in my head for a while and I finally needed to get it out.

This enables defining declarative key and/or value transformations in cases where neither Class- nor path-based converters can be applied gracefully. It is also the only way to express transforming the resulting property names in Typed objects without applying a converter to the entire containing type, which is cumbersome at best.

SPICE: apple/pkl-evolution#26

This also fixes a silly wart in the API for getting class property mirrors added in #1106.

Resolves #576

@HT154 HT154 force-pushed the annotation-converters branch 2 times, most recently from 1870188 to 274ba33 Compare November 29, 2025 20:57
@HT154 HT154 changed the title Add Annotation-based converters SPICE-0024: Annotation converters Dec 12, 2025
@HT154 HT154 force-pushed the annotation-converters branch 2 times, most recently from 97ac0af to df576b6 Compare December 22, 2025 23:38
@HT154 HT154 force-pushed the annotation-converters branch 2 times, most recently from 2d813fe to 192ed70 Compare December 23, 2025 01:13
Copy link
Contributor

@stackoverflow stackoverflow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Look good. One question:
As annotation converters run subclass -> superclass, you may get into cases where you can't override a superclass converter right?

// some parent module
open class Super {
  @SnakeCase
  myProperty: String
}

// my rendered file
class Sub extends Super {
  @CamelCase
  myProperty: String
}

Will render to my_property if I understood it correctly.

@HT154 HT154 force-pushed the annotation-converters branch from 192ed70 to 2b4f066 Compare January 9, 2026 20:33
@HT154
Copy link
Contributor Author

HT154 commented Jan 9, 2026

Look good. One question: As annotation converters run subclass -> superclass, you may get into cases where you can't override a superclass converter right?

Yeah, that's true. I wonder if this approach is worth revising. There are two main alternatives I see here:

  • Reversing the order, so annotations are walked from parent to child class.
  • Continue walking child->parent, but only allow each annotationConverters entry to be matched once per property. Example:
abstract class RenameConverter extends Annotation {
  abstract function rename(name: String): String
}

class SnakeCase extends RenameConverter {
  // ...
}

class CamelCase extends RenameConverter {
  // ...
}

output {
  renderer {
    annotationConverters {
      [RenameConverter] = (name, annotation, value) -> Pair(annotation.rename(name), value)
    }
  }
}

Here, only the CamelCase converter would run because it would be checked first and match against RenameConverter. Subsequently, SnakeCase would be checked and not match any unused converter entries so it would be ignored.

This approach is more complex in that it's more rules to keep in mind when working with annotation converters, but it's also simpler: the user does not have to keep track of how each annotation's implementation might interact.

Thoughts on which route might be preferable here?

@HT154 HT154 force-pushed the annotation-converters branch from 2b4f066 to 451d38e Compare January 9, 2026 21:06
@bioball
Copy link
Member

bioball commented Jan 10, 2026

Hmm.. I feel that it's fine that you can't override the annotations set on the superclass. I'm not actually sure if this is a problem.

Copy link
Member

@bioball bioball left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, looks pretty good!

@HT154 HT154 requested a review from bioball January 12, 2026 19:44
@HT154 HT154 force-pushed the annotation-converters branch 8 times, most recently from d7819e6 to 37cc4d8 Compare January 21, 2026 00:22
@HT154 HT154 force-pushed the annotation-converters branch 3 times, most recently from 7f434e1 to d885f71 Compare January 22, 2026 05:20
@HT154 HT154 force-pushed the annotation-converters branch from d885f71 to a312617 Compare January 22, 2026 19:46
Copy link
Member

@bioball bioball left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Getting pretty close!

Copy link
Member

@bioball bioball left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving to unblock!

But, some more suggestions (see below)

Also, we still need @Since annotations added to the new classes (like class Property in pkl:yaml).

@HT154 HT154 force-pushed the annotation-converters branch 5 times, most recently from 3f1ca4a to 1387ec0 Compare January 22, 2026 23:17
Copy link
Contributor

@stackoverflow stackoverflow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good.

@HT154 HT154 merged commit 73264e8 into apple:main Jan 23, 2026
17 checks passed
@HT154 HT154 deleted the annotation-converters branch January 23, 2026 20:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Output converters should allow selection for properties by Annotation

3 participants