
@qulert has joined the channel

Can someone confirm that after I compile code to bytecode, if I discard of the sources I can still run the bytecode with errortrace, since all the compilation does is expand the source plus some opts (inlining, etc)? I assume this is the case anyway because there’s no way to say raco make --mode=errortrace
, which is confusing because raco setup
has that option.

How is it possible to get a lambda into the scope of a place?

Apparently, I cannot just send a lambda to a place via a channel.

@joergen7 that’s right. a place is a separate racket process. Can you name the lambda and require it from the new place?

I planned to initialize the place with a struct that contains sets and functions.

I can convert the sets to lists and reconvert them at the receiving side.

but functions …

The functions, can be required in the place.

ok, but then the question is, are modules (module names) first-level objects in racket?

If that’s not a possibility for some reason, you can always serialize the sexps.

because I need to tell my place what to require.

you can tell the place what to require through a string. then you can dynamic-require it in the plac.e

very good, will try that.

ah one more thing…

is it possible to force a module to provide certain functions?

because I have to make my module work like a struct now. It has to have certain fields of certain types.

Not sure what you mean. Can’t you just provide
what you need from the module?

that’s what I’m trying right now.

So apparently I also have problems understanding how to use dynamic-require.

So dynamic require expects two arguments.

I don’t really get what the second must be. So I just set it to #f to see what happens.

then using the provided name, I always get an “unbound identifier” error, before the code is even executed.

I want the identifier to be bound by the dynamically required module.

I think I have this …

Oh! I can give it a symbol and then it will return me the value of what the symbol provides!

very good

Just found this gem by @mflatt: https://www.youtube.com/watch?v=rqXk7sqZEIk

gets the popcorns ready

@mflatt you mention @leif is working on a new compiler, did that happen already or were you talking about racket 7?

Interesting, first time I see the use of infix operators in racket code: (if ((length flags) . > . 5)
. Thought this was used mostly in contracts.

Is it correct to say that raco make
never builds zo’s with instrumentation enabled, i.e. errortrace? And the way to enable errortrace
on zo files on the command line is through raco setup --mode errortrace
?


this is different from racket 7

@pocmatos right, I think raco make
doesn’t have that option, although it would be a useful thing to add

Use of the dot infix notation is an apostasy. It is perhaps tolerable when doing outreach to nonbelievers. :smile:

@greg I found myself just writing it naturally the other day, which was weird

Also, from years of writing C/C++ I developed the habit of always writing comparisons in <
or <=
form. Why? To normalize comparisons and make it harder to swap them by accident. Hey it’s C. You play with fire, you collect rituals and spells of protection. ¯_(ツ)_/¯

Similarly CONSTANT == variable
so if I do =
by mistake I get an error not an assignment. ¯_(ツ)_/¯

OK sorry for OT. Back to work.

@mflatt Is it okay to change the kind of the lifted required scope from 'macro
to something like 'lifted-require
? Or should I use something like 'use-site
?

@greg that infix operator is in the raco setup
code… you might be sinning every single time you call it. :slightly_smiling_face:

(I don’t know how important/meaningful the names are.)

@samth thanks for confirming that. I am getting pretty confused as to how errortrace
works internally. For example, compiling with raco setup
without errortrace mode but then requiring errortrace-lib
and checking (instrumentation-enabled)
returns #true
.

@lexi.lambda I think it’s ok to use 'lifted-require
. The comment for the kind
field should be corrected to say that 'macro
as the kind
value has meaning beyond debugging.

Okay, thanks. I can update the comment as part of this change, if you’d like.

@pocmatos Loading errortrace will instrument only code loaded from source. In addition, loading errortrace causes code previously compiled with raco setup --mode=errortrace
to be preferred to bytecode created without --mode=errortrace
. Otherwise, code that is loaded from bytecode can still be used, but is not instrumented

@mflatt but if I don’t compile with errortrace and load errotrace-lib to install the compiler handlers in places, why does it tell me the code is instrumented? In this particular case, I was trying to find out if the code is instrumented to report this to the user. What I am attempting following our discussion together with @robby on places profiling (https://github.com/racket/racket/issues/2019) was to have a command line option to enable application profiling, but the application would initially check if its bytecode was compiled with errortrace and if not, tell the user that profiling is not possible and he should get an instrumented version of the application — only bytecode is distributed to endusers.

What do you mean by “why does it tell me the code is instrumented?” What are you using to determine if code is instrumented or not?

@lexi.lambda (instrumentation-enabled)

(instrumentation-enabled)
only controls whether or not errortrace will instrument future sources loaded. As the documentation states: > Affects only the way that source code is compiled

It doesn’t reflect anything about whether or not existing bytecode was compiled with instrumentation.

@lexi.lambda right… well, might be my English but to me that quote seems to mean that it affects the way the source code is compiled, as in, at the moment. It doesn’t mention the future compilation of the sources.

but i grant you that it’s my misinterpretation of the documentation.

which begs the question, is it possible to introspect whether the current bytecode has been instrumented?

Well, it does mean that it affects the way source code is compiled. But affecting the way source code is compiled can only mean affecting future compilation of sources. Adjusting the parameter certainly can’t be applied retroactively to previously-compiled sources, unless you have a time machine. :)

I don’t know of a way to detect if a particular bytecode file was compiled with errortrace instrumentation or not, but that doesn’t mean there isn’t a way to do it.

A good approximation would be to check whether a compiled module’s dependencies include errortrace/errortrace-key

@mflatt thanks, I will try that approach.

In the source for syntax-local-bind-syntaxes
, I see an undocumented optional argument extra-intdefs
that seems generally useful. Was this omission intentional?

It’s documented on HEAD.

It also only exists on HEAD.

(I added it a few days ago.)

Nice, thanks.

@mflatt is the compiled module dependencies, what you can obtain through module-compiled-imports
?

Yes

Perfect.

All, I have been noticing lots of old bugs, where either the discussion has died, the bug reported is in a very old version of racket or there’s just not enough information to reproduce the bug. Is there any long-term plan on how to deal with these?

@pocmatos there’s not really a long term plan, although many of the old bugs are still bugs

@samth indeed, but I ran through a few that really could be close, or the OP could be contacted for more info. in any case, if there’s no plan to deal with those, I will take action on I see them. thanks.

@pocmatos certainly taking action when you see something that’s fixed now, or where more info is needed, is quite helpful

What does it mean when syntax-local-value
says an identifier is “not defined as syntax”?

It means the identifier is either unbound or that it’s defined as a runtime variable (e.g. with define
/ let
), not as a transformer binding (e.g. with define-syntax
/ let-syntax
).

I think the error message is slightly different on Racket 6 and Racket 7; I forget if either one distinguishes between the two cases. But either way, you can find out if it’s the former or the latter by checking if identifier-binding
produces #f
or not.

Thanks!

I’m writing a macro that takes an identifier and decides how to handle its bound value in a predicate-based cond. (define-syntax (frob stx)
(syntax-parse stx
[(_ x)
#'(let ([v x])
(cond [(procedure? v) (v)]
[(evt? v) (sync v)]
[else v]))]))
During expansion, sometimes syntax-local-eval
can see v
. When it can, I would like to use it to simplify the expanded output. (define-syntax (fast-frob stx)
(syntax-parse stx
[(_ x)
(let ([v (syntax-local-eval #'x)])
(cond [(procedure? v) #`(#,v)]
[(evt? v) #`(sync #,v)]
[else #`#,v]))]))
When syntax-local-eval
fails, I get an exn:fail:contract:variable
. Is catching the exception and falling back to frob
a reasonable solution?

I’m not sure I understand. Is this a macro being used at phase 1, so #'x
is a phase 1 expression? I imagine yes, since you’re using syntax-local-eval
, but on the other hand, I’m not sure why this is a macro then and not just a function defined at phase 1.

This is based on a phase 1 function. Does that matter?

I just feel like I’m missing why frob
is not written as: (define (frob x)
(cond [(procedure? x) (x)]
[(evt? x) (sync x)]
[else x]))

I guess I meant to indicate that I sometimes want to apply frob
before run time.

I don’t really understand. If it’s intended to be used at phase 0, then syntax-local-eval
isn’t the right thing, since it evaluates an expression in the transformer environment. But if it’s intended to be used at phase 1, then it would always be before runtime by definition. Values don’t really cross phases by design, so I’m not sure what the purpose of such a macro is. Perhaps you could give an example of its use.

Say frob
belongs to a lazy evaluator that wraps the non-function arguments of a procedure call in thunks.

I want to analyze the thunkified version and eliminate spurious abstractions, when the information is available.

I think you’d need to do a syntactic analysis, then, no? syntax-local-eval
really is evaluating, not expanding. It allows you to evaluate a phase 1 value in a phase 1 environment. If your input is a phase 0 expression, syntax-local-eval
won’t ever do the right thing, since (1) the necessary runtime bindings won’t actually exist and (2) once you get the value out, you won’t be able to embed it back into a syntax object because procedures and events can’t cross phases.

Perhaps you want local-expand
instead?

I may just be going about this all wrong.

I’ve made a language for making complex synchronizable events. It’s easy to implement the constructs as macros or regular functions. I would like to make a macro that transforms a Racket expression into an event that evaluates the expression and returns its result.

For procedure applications, non-event arguments are wrapped in events that produce the supplied value.

This can generate a lot of events, so I want to replace parts of the expanded syntax with simpler equivalents, like pre-currying non-event arguments.

I got the idea from your Hackett post to inject un-evaluatable literals and then analyze those.

That got me far enough to use syntax-local-eval
on identifiers in racket/base
like +
and choice-evt
, but fails on everything else. That seems like another can of worms. I’d be happy to optimize where possible for now, then extend the possibilities as I learn how.

@jeapostrophe / @leif If you’re still taking RacketCon web site buglet reportlets: The title for Laurent Orseau’s talk seems wrong (seems to be a copy of Jon Zeppieri’s, How to Ask for the Time in Racket).

@dedbox Sorry, I ended up going home in the middle of that conversation and ended up doing things for much longer than I had anticipated.

I don’t think you want syntax-local-eval
. I think you probably want to use local-expand
to expand your language, then use some sort of post-processing to detect certain expression shapes using free-identifier=?
(whether directly or indirectly through syntax/parse
literals) and adjust them. You can write an optimizer as part of your language’s #%module-begin
that does that. I plan on doing something like that for Hackett.

I don’t know the details of your particular problem, but for things like applications to well-known curried functions, you can do things like statically associate information with particular identifiers, then using syntax-local-value
to detect fully-saturated applications and skip the currying (also something I eventually intend to do for Hackett).

Thanks for the follow up. That makes a lot of sense.

I’ve been implementing whole interpreters from scratch in Racket, except sometimes parsers. Leveraging the expander makes everything easier.

@greg Thanks! Whoops!

So far, the most useful part of the Hackett post is getting to see how local-expand
fits into a bigger picture. I wish we had more pragmatic examples of advanced topics like that.