steveh2009
2019-6-8 15:51:37

Coding convention question: Should constants be capitalized, separated by dashes for long names?


soegaard2
2019-6-8 15:54:16

The style guide doesn’t say anything about constants: https://docs.racket-lang.org/style/Textual_Matters.html#%28part._names%29


soegaard2
2019-6-8 15:56:25

But there is a tradition to write constants in all caps:



dave
2019-6-8 19:13:20

@dave has joined the channel


dave
2019-6-8 19:42:53

Mellow greetings. I’m experimenting with a language for manipulating deeply nested data structures, where some validation has to be deferred to evaluation time. Is there an idiomatic way of hanging on to source locations that late, so that I can report more useful errors? Currently my only thought as a Racket newbie is to use a macro that expands to some kind of struct that stores both my s-expr and its corresponding syntax object, so that I can do parallel traversal of both and have “the syntax object that matches the expression I’m currently looking at” to hand.


dave
2019-6-8 19:43:15

but, not knowing everything that I don’t know, I have no clue if that’s a terrible idea :slightly_smiling_face:


dave
2019-6-8 19:46:02

The runtime state I’ll be dealing with is a bunch of s-exprs that layer on top of each other, where the eventual flattened result must conform to a couple different schemas. I want to be able to report useful errors that show the provenance of a bad piece of structure in the final flattened structure, pointing back to the source location where it got defined, if that makes sense.


soegaard2
2019-6-8 19:50:46

Keeping the syntax object works. There are alternatives though. You can use a srcloc struct or perhaps Eastlund’s package: https://docs.racket-lang.org/syntax/Source_Locations.html?q=source%20location


lexi.lambda
2019-6-8 19:51:57

There are also correlated objects, which are like syntax objects but without the lexical context: https://docs.racket-lang.org/reference/linklets.html#%28def._%28%28lib._racket%2Flinklet..rkt%29._correlated~3f%29%29


dave
2019-6-8 19:53:49

Thanks both for the pointers! Sounds like there’s a bunch more reading in my afternoon :slightly_smiling_face:


dave
2019-6-8 20:08:23

is there a utility function somewhere to convert syntax objects to correlated objects? Seems like a straightforward “pull apart and reassemble” transformation, if I’m reading this correctly.


lexi.lambda
2019-6-8 20:14:12

I don’t think there is, but it’s probably because correlated objects are fairly new and I think were really mostly just intended for the bootstrapping process at the linklet layer. But I don’t see any reason they couldn’t also be used for other things.


dave
2019-6-8 20:21:30

Got it. Maybe it’s a bad idea for me to be using linklet internals for my own nefarious purposes, but worst case it’ll give me something to imitate with my own structure.


soegaard2
2019-6-8 20:22:05

How will you be using the source locations?


dave
2019-6-8 20:30:48

So, I’m using Racket to describe Terraform and Kubernetes objects, which are nested data structures that come with their own schemas. For instance, the schema might describe a shape like [(foo "bar") (baz (quux (zot 4)))], where baz.qux.zot must be a positive integer and foo can be anything. I want to be able to validate an expression against a schema, and be able to point to the precise source location of an error - something like baz.quux.zot must be a positive integer, but you gave it the value (not (a (number))) at my-config.rkt:45


dave
2019-6-8 20:32:28

Two complications are that I don’t always know the schema in advance, because e.g. Kubernetes lets you define custom types that you only discover when you go talk to a specific server; and the language I’m playing with lets you extend one expression with another, so you can override a deeply nested piece of expression A with expression B - and I want to properly track that, if B is the thing that doesn’t match the schema, I want to point there (and possibly also point out that it’s overriding A, which was defined in this other place)


dave
2019-6-8 20:33:16

I’m being a bit handwavy because, well, I’m still making it up :slightly_smiling_face: I’m very much in the experimentation phase.


dave
2019-6-8 20:35:44

I should add that I’m doing all this because, if I just flatten all the expressions extending each other into the final form and ship it off to the remote server, it’s going to give me various unhelpful errors. Best case, it’ll tell me that foo.bar.baz is 4, wanted a string, but because of all the extending stuff, it might not be obvious where that 4 came from in the source. And worst case it’s just going to tell me “this object doesn’t match the schema, go away”, so I need to do the validation locally to get any useful information.


soegaard2
2019-6-8 20:36:54

If you want DrRacket to color “my-config.rkt” red at 45 then you can use raise-syntax-error which needs a syntax object that contains the source location (but the actual value of the syntax object is not important).


dave
2019-6-8 20:37:36

Ah, fantastic! I was hoping for an easy way to do that!


greg
2019-6-8 20:44:31

Would it possibly make sense simply to parse again from scratch once you have a schema? Parsing with no schema is more like a “lint”, could this work with some schema. And parsing again with a specific schema produces something usable for real. That would have the advantage you can just use the normal read/expand mechanism including syntax and error-reporting, as-is. That would have the disadvantage that parsing again would be slower.


greg
2019-6-8 20:44:54

Maybe that’s a dumb idea. OTOH I like to try the dumb ideas, first. ¯_(ツ)_/¯


greg
2019-6-8 20:45:38

But if that truly is dumb, the ideas above from other folks sound great!


dave
2019-6-8 20:47:43

hmm. I don’t understand how I’d get the builtin syntax and error reporting. Can you expand on that? I suspect I’m not picturing things the right way.


dave
2019-6-8 20:48:33

I guess more specifically, given some external schema, how do I end up with something where builtin read/expand can give me useful errors without writing my own parser anyway?


greg
2019-6-8 20:50:13

You’d still need to write a parser. I thought you meant, “When I parse, I can report syntax errors and stuff like that. But I can’t report things like schema errors, because I don’t have the schema, yet.” So my suggestion was just, don’t parse so soon.


greg
2019-6-8 20:50:27

Or, the user parse soon as a kind of “lint”, if you want.


dave
2019-6-8 20:50:29

ah, I see.


greg
2019-6-8 20:50:38

But just parse again when you have a specific schema.


greg
2019-6-8 20:51:04

And then you can report the errors using the usual syntax. That’s all


dave
2019-6-8 20:51:48

yup, got it. That does make sense! Honestly I’ve been doing parsing early just because that lets me experiment with the code structure without having to start dealing with external schemas just yet.


dave
2019-6-8 20:52:23

And I think there’s a small advantage to a “lint” pass, in that it’ll report some typo-ish errors faster and without having to go talk to slow servers for information.


dave
2019-6-8 20:52:24

Thanks!


greg
2019-6-8 20:53:09

You’re welcome. Again, if that ideas turns out to be bad, then the suggestions above were really good. I didn’t mean to detour you.


dave
2019-6-8 20:54:15

Not at all! This whole expedition is an excuse for learning, which might produce useful software as a side-effect. So this is exactly what I’m looking for!


dave
2019-6-9 01:38:11

My modest progress so far, fwiw. Now have a struct that captures the source locations of its child expression, so I can parse through it and raise useful syntax errors.


dave
2019-6-9 01:42:29

huh, I guess slack doesn’t know how to highlight racket. http://pasterack.org/pastes/31923 then.