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

Compiletime reflection #43

Closed
HedariKun opened this issue Mar 23, 2019 · 23 comments
Closed

Compiletime reflection #43

HedariKun opened this issue Mar 23, 2019 · 23 comments
Labels
Feature Request This issue is made to request a feature.

Comments

@HedariKun
Copy link

will it have reflection ? if yes is it the same as go?

@medvednikov
Copy link
Member

I'm not sure yet.

Reflection is slow and can result in runtime errors.

I think I'll implement it with codegen, just like json decoding.

@HedariKun
Copy link
Author

if it would be something like c#'s it would be awesome,
like just adding an attribute to a func then take it from reflection to do stuff with it, it would be time saver in making API like

[url="/api-end-point"]
fn someFunction(w http.ResponseWriter, r *http.Request) {}

@tjpalmer
Copy link

I could see value in static reflection or a compiler API at some point. @medvednikov As you point out, this could generalize your json support (which some people won't want to use anyway, as more efficient serialization methods exist). But I agree that runtime reflection is at odds with V as I understand it today.

@ntrel
Copy link
Contributor

ntrel commented Apr 4, 2019

@tjpalmer Yes, compile-time reflection would be great. I've posted some thoughts on possible native V JSON decoding in a comment here.

@medvednikov
Copy link
Member

The syntax I have in mind:

fn decode<T>(data string) T {
        mut result := T{}
        for field in T.fields {
                if field.typ == 'string' {
                        result.$field = get_string(data, field.name)
                } else if field.typ == 'int' {
                        result.$field = get_int(data, field.name)
                }
        }
        return result
}

// generates to:

fn decode_User(data string) User {
        mut result := User{}
        result.name = get_string(data, 'name')
        result.age = get_int(data, 'age')
        return result
}

What do you think?

@medvednikov
Copy link
Member

@HedariKun about your suggestion.

vweb framework will have the following syntax:

['/post/:id']
fn (a App) show_post(id int) vweb.Result {
  post := a.posts_repo.retrieve(id) or {
     return vweb.not_found()
  }
  return vweb.view(post)
}

@ntrel
Copy link
Contributor

ntrel commented May 2, 2019

decode looks good, I think it needs to use something like result.$(field.name) = though. Perhaps local const values could be allowed:

        const fields = T.fields
        for field in fields {
                const id = field.name
                if field.type == 'string' {
                        result.$id = get_string(data, field.name)
                } else if field.type == 'int' {
                        result.$id = get_int(data, field.name)
                }
        }

I renamed typ to type, I assume that was a typo ;-)
For structs with fields of struct type we can recurse:

else if is_uppercase(field.type[0]) {
  const type = field.type
  result.$id = decode<$type>(data)
}

For arrays we can check field.type[0:2] == '[]' and then handle the element type like above.

@ntrel
Copy link
Contributor

ntrel commented May 2, 2019

We could call $identifier a string identifier. Compile-time for and if could be called inline. I think inline if shouldn't create a scope, so the body can declare variables for use after the if block - this is like D's static if. Maybe inline for and if should look different to their runtime versions.

@medvednikov
Copy link
Member

type is a keyword, just like in Go, so typ has to be used instead.

@medvednikov
Copy link
Member

V can be smarter with struct fields:

else {
  result.$field = decode(data)
}

Compile-time coding is tough, I want to make it as simple and light as possible.

@medvednikov
Copy link
Member

medvednikov commented May 2, 2019

Maybe to make this more consistent and simpler:

if field is string {
  result.$field = get_string(data, field)
} else if field is int {
  result.$field = get_int(data, field)
} else if field is struct {
  result.$field = decode(data)
}

@medvednikov
Copy link
Member

Even better:

result.$field = match field {
  string => get_string(data, field)
  int    => get_int(data, field)
  struct => decode(data)
}

@HedariKun
Copy link
Author

the later syntax seems better, also it is nice that the vweb will have that type of syntax but wouldn't it be good if we can make our own, like having ['something'] can also be used when creating other stuff, maybe discord bot and you specify the command name between [] or some other custom thing.

@medvednikov
Copy link
Member

but wouldn't it be good if we can make our own

[attr] is a method attribute that can be defined by developers for any method and accessed via reflection.

@HedariKun
Copy link
Author

oh neat~

@ntrel
Copy link
Contributor

ntrel commented May 13, 2019

I think requiring $if and $for for compile time code makes the code clearer for the compiler (giving better errors) and user:

$for field in T.fields {
  $if field is SomeType {

Let's define what's happening. Here I'd call field a symbol alias as it's not a value. $field means use the field name as an identifier token in code.

For ident is Type I think ident can be a variable or type. Other than with is I suggest we use type(field) to clearly get the field type, and something like field.stringof to get a string of the field name:

  result.$field = get_string(data, field.stringof)
result.$field = decode<type(field)>(data)
result.$field = $match type(field) {

See also #205 for some more compile time code generation.

@ntrel
Copy link
Contributor

ntrel commented May 13, 2019

field.stringof

Of course this could be field.name as in the current docs. Allowing field alone to get a string could be ambiguous if field is passed as a template argument, depending on what we allow in future to be passed as template arguments (see string template arguments in my referenced issue above).

The reason I prefer type(expr) over field.type is because expr can be a more complex expression than just an identifier, e.g. a + b. This can be useful in template code.

@medvednikov
Copy link
Member

I agree, compile time if, for, match should be distinguishable. $if, $for, $match seems to be fine.

@PavelVozenilek
Copy link

What I would like from meta functionality in compile time:

  • ability to enumerate source files, with their attributes
  • ability to enumerate all top level items in source files
  • ability to enumerate structure members and statements in functions, hierarchically, scope by scope
  • API which says "this item is used by these other items", like who is calling my function

This would allow me to implement e.g. this:

  1. Application specific tools to verify validity the code, e.g. each foo call has to be followed by reverse-foo inside the scope. This specific example could be perhaps handled in other way (I'd use RAII in C++), but the checks often go beyond such simple scenario.
  2. My own test runner. E.g. I would like to run only tests from recently modified source files, not everything.

@chanbakjsd chanbakjsd added Feature Request This issue is made to request a feature. discussion labels Jun 25, 2019
@nedpals
Copy link
Member

nedpals commented Mar 30, 2020

Update:
typeof() has already been implemented in v2 backend. Generics are now being stabilized in the new backend and there are now discussions on Discord about implementing interface{} (aka any).

@ntrel
Copy link
Contributor

ntrel commented Jul 24, 2020

Here I propose some new compile-time features for reflection and update the docs: #5962

@shelby3
Copy link

shelby3 commented Sep 15, 2020

I thumbs-downed this feature request, unless someone can explain why repeating Go’s design error will not be a problem for Vlang?

Runtime reflection in Go ostensibly was a design error that continues to have egregious implications they apparently did not contemplate when it was designed into the language:

  1. The JavaScript transpiler GopherJS thus can’t safely do dead code elimination, thus bloated JavaScript output.

  2. The new generics proposal is apparently handicapped by an inability to have type parametrization in methods presumably because of reflection.

@medvednikov
Copy link
Member

medvednikov commented Sep 15, 2020

@shelby3 like @ntrel mentioned we will have compile time reflection, not runtime reflection like in Go.

Actually we already have some of it working.

@danieldaeschle danieldaeschle added this to Stage 1 in Proposals via automation Jan 27, 2021
@danieldaeschle danieldaeschle moved this from Stage 1 to Stage 2 in Proposals Jan 27, 2021
@danieldaeschle danieldaeschle changed the title reflection Compiletime reflection Jan 27, 2021
@danieldaeschle danieldaeschle removed this from Stage 2 in Proposals Jan 27, 2021
@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 Request This issue is made to request a feature.
Projects
None yet
Development

No branches or pull requests

8 participants