Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

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 for typed attributes #7014

Closed
danieldaeschle opened this issue Nov 29, 2020 · 19 comments
Closed

Proposal for typed attributes #7014

danieldaeschle opened this issue Nov 29, 2020 · 19 comments
Labels
Feature/Enhancement Request This issue is made to request a feature or an enhancement to an existing one. Type: Specification Everything related to the formal specification of how V should behave

Comments

@danieldaeschle
Copy link
Member

danieldaeschle commented Nov 29, 2020

This would be super useful for our vweb framework which has some attributes. Using this technique we could remove compiler magic for the vweb module and make a more generic solution.

Requirements

  1. It should be able to define methods on it. Those methods can be looked up at compile time then and be called.
  2. It should be able to contain fields/parameters.
  3. It should not be able to pass an attribute as a type parameter in function arguments nor cast or instanitate something.
  4. It should not have any field visibility like pub or mut

A: struct attribute - attribute

an attribute struct shouldn't have struct embedding, pub mut, be initialized nor be used as a type parameter.
An example would look like:

enum HttpMethod { get post put delete patch }

[attribute]
struct Route {
    path       string
    method HttpMethod
}

// .get looks a little bit weird. we could use also a string with `'GET'` or something. but it's only an example here.
[Route{'/index', .get}] // or even [Route{path: '/index', method: .get}]
fn index() {}

B: attribute keyword

This would introduce another keyword but would be good as well is:

enum HttpMethod { get post put delete patch }

attribute Route(path string, method HttpMethod)

// .get looks a little bit weird. we could use also a string with `'GET'` or something. but it's only an example here.
[Route('/index', .get)] // or even [Route(path: '/index', method: .get)]
fn index() {}

Obviously, the last propsal would introduce more complexity to the compiler which could also slow it down. But the syntax will be shorter and structs wouldn't be used for different things.

Using attributes

Either attribute using is always like this: [Route('/index', .get)].
Or if we decide to use a castraed form of a struct, we could use the syntax [Route{'/index', .get}]

@danieldaeschle danieldaeschle added the Feature/Enhancement Request This issue is made to request a feature or an enhancement to an existing one. label Nov 29, 2020
@danieldaeschle danieldaeschle changed the title RFC: Proposal for custom attributes Proposal for custom attributes Nov 29, 2020
@IngwiePhoenix
Copy link

Since attributes kinda remind me of TypeScript's decorators and their proposal in ES6, why not borrow from them outright and change it a little?

// Most identifier/keyowrd names are short - so I decided to stick with it.
attr fn(f fn()) Route(path string, method HttpMethod) {
  router.register(
    path: path
    method: method
    callback: f
  )
}

Treading attribute functions like they had a context or were a method might allow to specify where and when attributes would be allowed - but that is probably way over the top.

Also if I recall correctly, in Rust, you have to specifically import macros as well to use them. With attributes, it should probably be the same to be on the save side to make sure two attributes from different modules would not clash.

import webframework
import attrs webframework // explicitly import the webframework attributes.

@danieldaeschle
Copy link
Member Author

@IngwiePhoenix Good idea. Python also has decorators. But decorators are not the same as attributes. Take a look a t C# attributes to see something similar.
I'm thinking the whole day about how we could implement them and what they need. Will update this soon.

@danieldaeschle danieldaeschle self-assigned this Jan 6, 2021
@Delta456
Copy link
Member

Delta456 commented Jan 6, 2021

Wouldn't this make the language bigger?

@danieldaeschle
Copy link
Member Author

danieldaeschle commented Jan 6, 2021

Alex gaves his ok for it. It just needs a solid specfication.
image

@danieldaeschle danieldaeschle added the Type: Specification Everything related to the formal specification of how V should behave label Jan 6, 2021
@spaceface777
Copy link
Member

You can already implement custom attributes via V's compile-time $for/$if, although these are currently very limited to very basic things. I'd rather have more powerful compile-time features (e.g. calling functions at compile-time), rather than introducing new language features.

@danieldaeschle
Copy link
Member Author

@spaceface777 I will extend this. I forgot to add the definition that those custom attributes are typed.

@danieldaeschle
Copy link
Member Author

I see some flaws if we have untyped attributes:

  1. The compiler should catch user errors
    if one would do this:
[get]
['/myroute']
[/route-without-string]
[inline]
pub fn (mut app App) my_route() Result {
    return app.text('My Route')
}

this results in: having the follwong routes: /nline, /myroute, /route-without-string
If we would have typed attributes this can be prevented by the compiler.

  1. more possibilities with attributes (e. g. multiple parameters)

@danieldaeschle danieldaeschle changed the title Proposal for custom attributes Proposal for typed attributes Jan 6, 2021
@spaceface777
Copy link
Member

  1. I don't think that attributes handled by the compiler (e.g. inline, export:, etc.) should be included in FunctionData.attrs, or there should at least be a way to differentiate them from custom attributes (maybe make attrs have a custom: bool field?)

Also, functionally, what's the difference between an attribute with a string (['/myroute']), and an attribute with an ident ([/route-without-string])? From a user's perspective, it looks as if they'd work the same, so maybe one syntax could be deprecated, or the difference should be documented otherwise.

Type checking could still be done by the user at compile-time, if we had (for example) a compile-time $error() function that would produce custom compiler errors, but automatic checking by the compiler would be nice.

@danieldaeschle
Copy link
Member Author

danieldaeschle commented Jan 6, 2021

I see an advantage to define inline and export: as typed attributes as well. It would be in the code and every user can see it. It can also be documented in the code which will be in vdoc then.

Non-typed attributes wouldn't give the ability to have middlewares in attributes:

[attribute]
struct Authorize {}

pub fn (a Authorize) before_request() {
    // some jwt stuff and return 401 if not authorized
}

[Route('/settings', .get)]
[Authorize]
pub fn (mut app App) settings() {
    // ...
}

It would be the same as C# has. Very powerful.

@danieldaeschle
Copy link
Member Author

Also, functionally, what's the difference between an attribute with a string (['/myroute']), and an attribute with an ident ([/route-without-string])? From a user's perspective, it looks as if they'd work the same, so maybe one syntax could be deprecated, or the difference should be documented otherwise.

It's a bug, not a different functionality. It's just not easy to catch all cases which the user can do wrong. With typed attributes compile time check would be easier.

@spaceface777
Copy link
Member

yeah, ok, I see your point and agree :)

@dumblob
Copy link
Contributor

dumblob commented Jan 6, 2021

Well, do I understand it correctly, that an attribute [...] (i.e. anything between square brackets) would be arbitrary standard V code? That'd be awesome as there'd be no need for the programmer to learn any new syntax, everything would be type checked, it'd be by definition extensible, there'd be no need for a different parser, no need for a different checker, etc.

@danieldaeschle danieldaeschle removed their assignment Jan 24, 2021
@tomByrer
Copy link

I don't really like the [square bracket] notation, sorry. I don't plan to learn C#, where I guess many got used to it. Makes it seem too 'magical', & I've been programed to see everything in a square bracket as a list.

I'd prefer more plain text notation like IngwiePhoenix's idea.

The idea of 'attributes' would make things like vweb much easier to program for sure. Maybe make it a DSL for vweb, & see if you like it enough for all of V?

@larpon larpon closed this as completed Jan 27, 2021
@larpon larpon reopened this Jan 27, 2021
@danieldaeschle
Copy link
Member Author

danieldaeschle commented Jan 27, 2021

@larpon why close and reopen? :D

@tomByrer Yeah, it's your personal preference. But does it matter if it's [] or @ like in Java? It's really a minor thing in this case.

This issue is more about having typed attributes rather than chaning the attribute feature. What IngwiePhoenix showed are not attributes. That are decorators which is a different technologie.

@IngwiePhoenix
Copy link

Yes - and no. Let's use __attribute__(visibility("default")) for example. It changes the symbol visibility on a function in C. It is a attribute, but also a decorator in the sense that it modifies the function - at least in a way.

Say the [extern:] attribute was formalized as a function, it'd probably look something like this:

attr fn(mut f &FunctionData) extern(name string) {
  // ...
}

f would be the function associated with the [extern:] attribute. But, this definition right there also goes hand in hand with how a TypeScript or JavaScript decorator would work; it's basically just a function receiving another to fulfill a purpose. Be it to change visibility - or as it is used in places like the TypeScript framework Nest Framework, to configure routing.

They are not exactly the same, but basically work on even grounds. Just that in C __attribute__(...) can not be user-defined and is predefined by the C compiler itself, whilst decorators can be user defined.

But if you use @ or [] is just a syntactic discussion - on a functionallity level, an attribute as known from C and a decorator from JS/TS are quite close.

@danieldaeschle
Copy link
Member Author

Yeah, I know everything you mentioned. My understanding is that V has no decorators like Python or TypeScript but attributes like C# which are handled at compiletime which is faster.

@IngwiePhoenix
Copy link

Yeah, right now all attributes are handled at compile time and in the generator - cgen, for instance.

Technically, if the comptime feature was extended to define compiletile functions, attributes defined per library wouldn't be far off.

@danieldaeschle
Copy link
Member Author

We won't use compile time functions for this case. This doesn't work. Compile time function don't have access to struct fields.

@tomByrer
Copy link

tomByrer commented Jan 28, 2021

it's your personal preference

That's true! I'm shopping for a language with few 'magic characters'; faster to learn & teach IMHO, & I don't have to think twice if [] = array or not.
But I understand some would prefer code to be more left-aligned as possible.

I do like @ better, since my mind I read it as at, so it feels more like a flag.

@vlang vlang locked and limited conversation to collaborators Sep 22, 2021

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
Feature/Enhancement Request This issue is made to request a feature or an enhancement to an existing one. Type: Specification Everything related to the formal specification of how V should behave
Projects
None yet
Development

No branches or pull requests

8 participants