Fork me on GitHub
#vim
<
2017-05-03
>
jebberjeb21:05:18

Glad to get some discussion on it ^^

jebberjeb21:05:25

@ingvij Did you mean using a macro to generate the functions from the stored metadata?

hkupty21:05:13

Yes. Overall, the functions are very similar

jebberjeb21:05:38

I'm interested in knowing how that will prevent bugs due to API changes mostly. That's one reason I liked letting the generated versions live side-by-side.

jebberjeb21:05:45

Well not liked, but tolerated.

hkupty21:05:14

Not actually prevent bugs.. AFAIK, neovim API versioning won't break as API version bumps.. Actually, this will make simpler (by auto-generating the functions) to bump as neovim bumps their API.

hkupty21:05:44

If we have static definitions of each function, we're entitled to keep them as the API evolves

hkupty21:05:57

and we possibly break users from using newer features

jebberjeb21:05:12

Right, rather than adding the generated source, you'd only have to add the metadata resource, in that case.

hkupty21:05:28

It doesn't have to be a macro, though

jebberjeb21:05:30

But the namespaces are all API versioned, so how could they break currently?

hkupty21:05:53

It can be negotiated upon starting (by requiring the api version as a parameter)

jebberjeb21:05:11

It does that currently. It requires the api level.

hkupty21:05:37

Then why we have them stored? I might have missed something..

jebberjeb21:05:07

Right, you could just have a macro which generates them all using the stored data + api level. I was a little torn between macro + stored metadata vs generated code myself. I see pros and cons to both.

jebberjeb21:05:25

Here's one problem...

jebberjeb21:05:36

I take it back -- I can't remember exactly why I went that direction.

jebberjeb21:05:05

Macro should work right? By the time dependent code is evaluated, that macro should have expanded to create whatever namespaces and functions it needs.

jebberjeb21:05:57

Maybe that was my problem with it -- that central macro has to be included in your code somewhere, else it won't even compile.

hkupty21:05:23

The thing with keeping the generated code is, as soon the API evolves, we're growing the codebase with code we can't actually touch. After a few bumps, we'll have several files full of static content making it very hard to track things down..

jebberjeb21:05:40

You mean in terms of like, bug fixing

hkupty21:05:39

Not only that, there will be several functions left there we won't ever be able to remove and we'll have to be careful about changing the underlaying code..

hkupty21:05:53

It adds too much entropy with little return..

jebberjeb21:05:35

How would using a macro to generate everything based on the stored metadata solve that? Wouldn't that stored metadata be just as off limits as the generated code?

jebberjeb21:05:10

FWIW, I'm not being deliberately obtuse here -- and normally wouldn't want to generate code, and fought doing it. Just trying to wrap my head around this all.

hkupty21:05:03

We don't need to use a macro.. We can delay the function generation to happen right after connecting on neovim. Since we just negotiated the API version to use, we can generate the functions from there.. Not the best approach, but it's a macro alternative.

jebberjeb21:05:23

That makes it really tricky on dependent code though.

jebberjeb21:05:50

Say you're writing a plugin. When you eval your plugin code, it will complain that namespaces and functions don't exist (unless you've interned all of that stuff already).

jebberjeb21:05:14

So you're dependent on the existence of the connection -- believe me, I wanted it to work that way, and coded it that way originally.

hkupty21:05:56

What if we have a looser structure, such as (nvim/api "nvim_get_var" "g:my_var"), not having a static implementation of it?

jebberjeb21:05:09

ah, yes 🙂

jebberjeb21:05:15

this is my great dilemma

jebberjeb21:05:05

When I got to that point my interpretation was that would not be entirely consistent w/ the goals of the Noevim API client stuff.

jebberjeb21:05:32

They provide this metadata complete w/ types, I'd assume, because they want first class objects, functions, methods, whatever

hkupty21:05:48

The real thing for me is not having a static snapshot of the API, since it will be different for every bump on their side..

jebberjeb21:05:20

I agree, I'd rather not as well. I just don't see a way around it that allows you to evaluate your plugin code w/o some ceremony.

jebberjeb21:05:56

And to get around that, my solution was static snapshots per API level -- because according to what I read, that should be non-breaking.

jebberjeb21:05:12

And then include the API level in those snapshots.

jebberjeb21:05:26

I hope I'm just missing something obvious.

hkupty21:05:30

Then we're back to macro x static code

hkupty21:05:00

I'm just brainstorming here, now, so forgive me if I say something too stupid..

jebberjeb21:05:10

likewise, and thank you for discussing

jebberjeb21:05:23

I've thought / written so much about this in trying to make these decisions solo last year.

jebberjeb21:05:46

Glad to finally have a chance to air it out. The static generated code bugs the shit out of me.

jebberjeb21:05:12

So let's say you're in your editor and you're building a plugin. And you write some code to require a namespace. How do you ensure that macro is evaluated somewhere before that require happens?

jebberjeb21:05:09

That's sort of the crux of it for me, I think. The only way I could see was to tell a dev in the docs "You have to require neovim-client.core, and put (generate api-level) somewhere in your code". And that just felt weird. As much as I hate it, it felt more weird than generating the code statically.

jebberjeb21:05:35

I looked for example of precedent elsewhere and couldn't really find it.

hkupty22:05:09

> How do you ensure that macro is evaluated somewhere before that require happens? Is it too absurd to use a lein/boot plugin? (legitimate question)

jebberjeb22:05:07

Yes, I'd prefer dealing with static code to getting into bed with Leiningen.

hkupty22:05:15

No problem

jebberjeb22:05:23

I guess it's worth discussing, but I'm not a fan these days.

hkupty22:05:25

I understand the downside

jebberjeb22:05:30

I'm mostly out of the Leiningen game.

jebberjeb22:05:52

I can totally see how people would prefer that to a bunch of stored generated code.

jebberjeb22:05:46

I just use it for the classpath these days, and that's it. I honestly haven't used Boot.

jebberjeb22:05:43

Probably worth discussion though.

hkupty22:05:18

This is probably my last good idea... What if we expose a command (on neovim) or a function that generates all those functions for the supplied API level and we leave that on the plugin side?

hkupty22:05:42

I mean, it is still generated code that will statically live on a repository, but we don't need to keep all possible versions on our side... Instead, the plugin author decides on which version to support and when to bump...

hkupty22:05:30

This is a one-time command/function to run and we expose this functionality while we don't pollute our codebase...

jebberjeb22:05:45

Hrm, so they ship the generated client code w/ their plugin?

jebberjeb22:05:43

I'm kind of torn -- think I need to sleep on that one. It's ceremony, but it'd be easy to document and straightforward. And I think it's something plugin developers would tolerate.

jebberjeb22:05:58

It's simple.

jebberjeb22:05:14

That's definitely my favorite alternative so far. For a general purpose library that you just grab from clojars and use I probably wouldn't like it, but this thing is super niche. I think at the point where you're building Neovim plugins in Clojure, maybe you won't get too turned off by having to run one command line before diving in.

hkupty22:05:16

> For a general purpose library that you just grab from clojars and use I probably wouldn't like it, but this thing is super niche. I totally agree

hkupty22:05:50

I'll try to think of another alternatives, but this seems a good enough approach without resorting to lein plugins, injected macros or black magic..

jebberjeb22:05:18

I think -- not sure, but looking -- that there are some other niche libraries that do something similar in the Clojure ecosystem.

jebberjeb22:05:39

Trying to find some precedence so we could say, we do it like X.

jebberjeb22:05:47

(and for my peace of mind)

jebberjeb22:05:57

I'm liking it, but would like to give it a little hammock time. One last plug for storing all of the generated code: it's actually decent documentation of what's changed between API levels. Also, while it is sort of ugly, it's more or less benign. API levels change very infrequently (supposedly). Specifically, we've only gotten 0, 1 & 2 over the last few years. It would be different if we were generating side-by-side versions of client code for every AWS service, for example.

jebberjeb22:05:58

I guess these are also arguments in favor of making the developer perform a one-time generation as well. It's pretty darn close to the same thing.

jebberjeb22:05:20

anywho, thanks for brainstorming. I hadn't even considered that last alternative, but I'm liking it. Back in a bit.

hkupty22:05:40

No problem! It was a nice session! Cheers!