Skip to content

Attributes #24

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

Attributes #24

wants to merge 1 commit into from

Conversation

nrc
Copy link

@nrc nrc commented Feb 24, 2025

Design doc for attributes (@settings, etc).

Signed-off-by: Nick Cameron <nrc@ncameron.org>

Proposed changes:

- Inner vs outer attribute semantics
Copy link

Choose a reason for hiding this comment

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

Instead of inner and outer, could we call them item attributes and scope attributes, respectively? Seems clearer.

Copy link
Author

Choose a reason for hiding this comment

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

I like item attr, but I find 'scope' a bit ambiguous. I was hoping to not use either terminology in user-facing docs, just named/unnamed and explain how they apply

item ::= ... | fn_decl | const_decl | import | inner_attr | outer_attr item
stmt ::= ... | const_decl | outer_attr stmt

inner_attr ::= `@` `(` (annot_item,)* `)`
Copy link

Choose a reason for hiding this comment

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

The lack of identifier after the @ for inner attributes makes it awkward to use many, unrelated attributes for an item. Instead of them looking like function calls, they would need to be differentiated by keyword arguments. An example I'm thinking about would be in Rust #[derive(Clone, Serialize)] and #[serde(rename_all = "camelCase")] on a struct. How would you do the equivalent here?

@(derive = [Clone, Serialize], serde = { rename_all = camelCase })

I know KCL is very different from Rust, so the specifics don't apply. But in most languages that have item attributes, it's common to want to apply multiple, unrelated attributes to the same declaration.

I think I'd prefer a different token or tokens the way Rust does it with # vs. #!.

Copy link
Author

Choose a reason for hiding this comment

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

I was thinking like:

@(derive = [Clone, Serialize])
@(serde = { rename_all = camelCase })

So, the logic here is that the name after the @ for inner attrs is showing the target of the attribute, whereas with outer attrs the target is always the following item


## Issues

- "Attributes" or "annotations"? I prefer the former, we've been using a mix, but mostly the latter. Other languages use either or both, no consensus.
Copy link

Choose a reason for hiding this comment

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

I think I'd choose attributes too. It's pretty arbitrary, as long as we stick with one. The only theme I've seen maybe hinted at is that annotations have no runtime effect by default. But it's all just metadata.

Comment on lines +117 to +118
- Syntax overlap with `@` for 'self'
- Remove `@` on self-arg once we've finished the kwarg migration
Copy link

Choose a reason for hiding this comment

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

Can we remove the @? I thought someone said that we needed a way to distinguish between a regular function and one that has a "self" parameter.

An alternative is how Python does it with a separator between positional and named parameters. I don't particularly like this, but it's optimized so that in the common case, the separator is rarely needed at all. For KCL, it would potentially allow us to free up the token.

If we need to keep it, couldn't we use basically any other token?

@outer

@!inner
fn foo(!positional: Plane, named: string): Sketch {}

// Attribute on the positional parameter.
fn foo(@!inner !positional: Plane, named: string): Sketch {}

Copy link
Author

Choose a reason for hiding this comment

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

"I thought someone said that we needed a way to distinguish between a regular function and one that has a "self" parameter." - hmm, yeah

"If we need to keep it, couldn't we use basically any other token?" - yes

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.

2 participants