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

[Proposal] Stringly typed macros #13604

Closed
OzieGamma opened this issue Sep 5, 2016 · 12 comments
Closed

[Proposal] Stringly typed macros #13604

OzieGamma opened this issue Sep 5, 2016 · 12 comments

Comments

@OzieGamma
Copy link

Hi,

I was thinking about the proposed generators. Can this not be expanded to macros?

In the sense of LISP/Scala/Rust macros.

I was thinking of a syntax similar to Rust (note the '!'):

class Example
{
    NotifyPropertyChanged!(public int Id {get; set;})
}

The macro is defined in another, already compiled dll, similar to analyzers. We could even reuse the same infrastructure.

Eg:

[Macro]
public static class Macros
{
    public PropertyNode NotifyPropertyChanged(PropertyNode node)
   {
   }
}

NB: I typed this from my phone, I am not sure of exact Node names but you get the point.

@OzieGamma
Copy link
Author

We could even implement type generators this way:

File GeneratedTypes.cs

GenerateModels!("Server=...")

File DbModelGenerator

public class DbModelGenerator
{
    public static IEnumerable<TypeDeclaration> GenerateModels(ConstantStringNode node)
    {
        ...
    }
}

@dsaf
Copy link

dsaf commented Sep 5, 2016

I was thinking of a syntax similar to Rust (note the '!'):

Depending on implementation it might conflict with non-nullability enforcement in future.

@HaloFour
Copy link

HaloFour commented Sep 5, 2016

Generators can be effectively expanded to macros, and I expect that in numerous scenarios they will be. But they wouldn't need any new syntax to do this. I imagine that many scenarios will arise using attributes:

class Example
{
    [NotifyPropertyChanged]
    public int Id { get; set; }
}

What advantage would there be to wrapping that in something that looks like a method call?

@orthoxerox
Copy link
Contributor

I think for stringly-typed use cases generators should be enough. Strongly-typed macros will be a much more difficult endeavor and are probably better covered by compiler plugins (although you would need multiple plugins for the parser+syntax tree, bound tree, and optional lowerer and emitter).

@OzieGamma
Copy link
Author

I prefer explicit macros to the generators. The problem I have with the generators is that they use attributes. It can be unclear what is really happening.

I might be wrong but I think my proposal just requires changing the parser and then invoking the macro on whatever tree was parsed. I dont know the C# grammar that well so there might be conflicts there.

I mean Analyzers do exactly what I want to do. The only difference is the extra syntax and that you only change the code in memory.

@HaloFour
Copy link

HaloFour commented Sep 5, 2016

@OzieGamma

The problem I have with the generators is that they use attributes.

They don't "use" anything, attributes just provide an obvious and easy built-in way to trigger a generator to do something. But they aren't limited to members or types annotated with any given attribute; they can generate code based on any convention they desire. You could also use a syntax built into trivia (comments) to drive generators if you wanted.

Considering that generators will cover the use cases I can't imagine that a completely separate syntax would be considered just for a flavor of generators. And the syntax above seems quite alien to C#.

@OzieGamma
Copy link
Author

Hum, fair enough. I am one of those who hates attributes. I think they look like magic.

What I like about my syntax is that it clearly shows you are invoking a method with a tree at compile time to generate a new tree.

Aren't generators limited to invoking original() ? Can they change the tree of original?

@HaloFour
Copy link

HaloFour commented Sep 5, 2016

@OzieGamma

It looks like you're invoking a method over a declaration, which doesn't make a lot of sense unless you know about how the compiler happens to parse said declarations. Shrug, not my preference.

Source generators can emit anything they want and they can replace any member(s) they want. Those replaced members can call the original version of those members by using the original keyword, but to my knowledge that's completely optional. They are a pretty big blank canvas. It would be nice if the generator could replace the current tree instead of emitting source, though.

@OzieGamma
Copy link
Author

@HaloFour yes but they still can't inspect the Tree of original, can they?

Can the generator attributes have parameters? Can I generate types? How does the generator know how many arguments original accepts?

Maybe I underestimate the current generators. The syntax doesn't really matter to me. I care more about having access to the full Tree and being able to generate a new Tree.

@HaloFour
Copy link

HaloFour commented Sep 5, 2016

My understanding is that generators work a lot like analyzers in that they can inspect the parsed syntax tree as a part of the compilation process. The difference being that they can inject extra source files into the compilation. Those source files can do anything that any source file in that project can do. The replace and original keywords can then be used by generators when emitting a partial class definition to affect existing members.

So you can read the tree, but instead of generating a new/replacement tree you inject a string of source. I agree that it would be nice to be able to modify the tree in place, but one advantage to having source is that the IDE could easily offer the result to view, like it does with designer files and t4.

Since they can injecr arbitrary source they can definitely inject new types.

@OzieGamma
Copy link
Author

Ah ok. They can inspect the tree. So it's basically what I proposed but with replace and original as extras?

Feels weird to me

@gafter
Copy link
Member

gafter commented Dec 28, 2017

We are now taking language feature discussion in other repositories:

Features that are under active design or development, or which are "championed" by someone on the language design team, have already been moved either as issues or as checked-in design documents. For example, the proposal in this repo "Proposal: Partial interface implementation a.k.a. Traits" (issue 16139 and a few other issues that request the same thing) are now tracked by the language team at issue 52 in https://github.com/dotnet/csharplang/issues, and there is a draft spec at https://github.com/dotnet/csharplang/blob/master/proposals/default-interface-methods.md and further discussion at issue 288 in https://github.com/dotnet/csharplang/issues. Prototyping of the compiler portion of language features is still tracked here; see, for example, https://github.com/dotnet/roslyn/tree/features/DefaultInterfaceImplementation and issue 17952.

In order to facilitate that transition, we have started closing language design discussions from the roslyn repo with a note briefly explaining why. When we are aware of an existing discussion for the feature already in the new repo, we are adding a link to that. But we're not adding new issues to the new repos for existing discussions in this repo that the language design team does not currently envision taking on. Our intent is to eventually close the language design issues in the Roslyn repo and encourage discussion in one of the new repos instead.

Our intent is not to shut down discussion on language design - you can still continue discussion on the closed issues if you want - but rather we would like to encourage people to move discussion to where we are more likely to be paying attention (the new repo), or to abandon discussions that are no longer of interest to you.

If you happen to notice that one of the closed issues has a relevant issue in the new repo, and we have not added a link to the new issue, we would appreciate you providing a link from the old to the new discussion. That way people who are still interested in the discussion can start paying attention to the new issue.

Also, we'd welcome any ideas you might have on how we could better manage the transition. Comments and discussion about closing and/or moving issues should be directed to #18002. Comments and discussion about this issue can take place here or on an issue in the relevant repo.


I am closing this issue because discussion appears to have died down. You are welcome to open a new issue in the csharplang repo if you would like to kick-start discussion again.

@gafter gafter closed this as completed Dec 28, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants