Skip to content
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

Fragmented declarations #4203

Open
lrhn opened this issue Dec 11, 2024 · 9 comments
Open

Fragmented declarations #4203

lrhn opened this issue Dec 11, 2024 · 9 comments
Labels
feature Proposed language feature that solves one or more problems

Comments

@lrhn
Copy link
Member

lrhn commented Dec 11, 2024

The enhanced parts and augmentations features makes it easier to contain the implementation details of a class in one file, while defining the signatures in another. Possibly even an implementation guarded by a conditional part directive.

Maybe this can also be achieved by a less complicated feature than the currently proposed augmentations:
"Fragment declarations" are like augmenting declarations in that more than one declaration can exist with the same name in the same library or scope, and they are combined into the actual API and implementation.
Unlike augmenting declarations at most one of the declarations for a function/member can be concrete. All other declarations must be signature declarations which only specify the API (kind, types, capabilities), but no implementation details (body, initializer lists, default values).

That means that there is no need for an augmented feature, since there is no augmented implementation to access.
There is also no way to change an existing implementation, so this is entirely a code management feature, and possibly (using conditional parts) a patch-like feature.
It may not be enough for macros, if they need to augment existing implementation, but it can be enough for manually written modular code, maybe even for some code generation.

(No extra keywords needed, just allowing multiple declarations of the same kind in the same namespace, as long as there is never two concrete declarations for the same thing, and at least one for declarations that cannot be abstract. Can allow, fx, part class Foo on declarations off classes, or similar, which so not declare a superclass. May need new syntax for declaring signatures for static members and constructors, which cannot be abstract today.)

And there is no ordering dependency, not unless two class declarations are both allowed to add mixins.

@lrhn lrhn added the feature Proposed language feature that solves one or more problems label Dec 11, 2024
@tatumizer
Copy link

I admit I don't have a mental model of how this all works, and maybe I shouldn't comment, but if the following is silly, I am ready to delete this comment.
Suppose you have a bowl with 2 cups of flour in it. Then somebody else adds 2 eggs. Apparently, the idea is to prepare the dough. Then somebody else adds 1 bottle of perfume. Nobody really knows how all these components add up, and what the goal of the exercise is. True, everybody is just adding stuff, but while adding, they rely on the assumption that no one will later add anything else, and whatever is NOT there at the moment, still won't be there at the end.
Don't know what to make of this. 😕

@lrhn
Copy link
Member Author

lrhn commented Dec 12, 2024

The entire point is to allow you to modularize a single library in a type safe way.

With no other features, you don't really need the signature declarations, it's just a way to spread a class over multiple files.

If we include conditional part directives, it's a way to specify a signature, and have a platform dependent implementation which is guaranteed to have that signature.

With code generation, macros or plain, it allows generated code to supply the implementation of an already specified signature, but not the more complicated feature of changing or wrapping existing implementation, which is one of the biggest sources of complexity in the augmentations feature.
So it's basically a slightly scaled back augmentations feature, which still gives me what I need.

@tatumizer
Copy link

I see. It's for a single library, where each part is aware of what other parts are doing. 👍

@ykmnkmi
Copy link

ykmnkmi commented Dec 13, 2024

Would it work the same as the @patch annotations in the SDK? This annotations looks cleaner and easier to use than augmentation.

@tatumizer
Copy link

@lrhn:
Having said this ("👍" ), I'm still musing along these lines:
If your "same-library" argument is important (it is!), then what happens with different libraries? Sure, this difference is reflected in the fact that we should use augment in one case, and no augment in the other, but...
Does the keyword augment magically resolve the "dough with perfume" paradox?
If not, then what?
Maybe you can agree that some conditions, restrictions, discipline etc. must be imposed on macro annotations to make them cooperate nicely? (Without some discipline, their "composability" might become a mirage).

@lrhn
Copy link
Member Author

lrhn commented Dec 13, 2024

The augment feature is also entirely within a single library, no different in that.

You can locally see the gaps in the implementation, but from the outside you can only see the single unified facade.

@tatumizer
Copy link

The augment feature is also entirely within a single library

It's within a library, in a sense that after all macro annotations are applied, the augment declarations find themselves residing in the same library, but the corresponding macros themselves are in different libraries, written by different people, who are not even aware of each other's existence. Your statement would be true if we talked about augmentations with no reference to macros, but they were introduced specifically to address the needs of macros.
(this is probably off-topic here?).

@DanTup
Copy link

DanTup commented Dec 17, 2024

Unlike augmenting declarations at most one of the declarations for a function/member can be concrete. All other declarations must be signature declarations which only specify the API (kind, types, capabilities), but no implementation details (body, initializer lists, default values).

What is the value/purpose of the "abstract" member declarations?

Eg. if I have:

class A {
  void foo();
}

// ...

augment class A {
  void foo() {
    // Implementation
  }
}

If exactly one concrete implementation must always be provided, what does void foo(); actually add/do?

@lrhn
Copy link
Member Author

lrhn commented Dec 17, 2024

Having a declaration which must have the same signature as every other declaration of that member, and at most one can have an implementation, just allows you to write redundant information. Which is usually not good for anything except showing intent and ensuring that everybody agrees on the signature. Not unless the augment/fragment is included using a conditional part directive, then it ensures that all such parts satisfy the same interface. I want that. :)

And with macros or other code generation, it allows you to write a signature, and have a generated member implement that. It allows less than full augmentations, but also avoids a lot of complexity. It's a different, concrete and consistent design point in the space for adding implementation, which might be enough for some things.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Proposed language feature that solves one or more problems
Projects
None yet
Development

No branches or pull requests

4 participants