jgeddes
2022-5-4 10:30:02

When I provide with contract-out a struct definition, where the struct has a super struct, there does not seem to exist the accessor for the fields that come from the super struct. That can’t be right, surely? Am I just missing something? (Example to follow)


jgeddes
2022-5-4 10:30:30

#lang racket/base (require racket/contract) (module *mod* racket/base (require racket/contract) (provide (contract-out (struct sup ([fld1 number?])) (struct sub ([fld1 number?] [fld2 number?])))) (struct sup (fld1) #:transparent) (struct sub sup (fld2) #:transparent)) (require '*mod*) (define S (sub 1 2))


jgeddes
2022-5-4 10:31:05

After this, however. > S (sub 1 2) > (sub-fld2 S) 2 > (sub-fld1 S) ; sub-fld1: undefined; ; cannot reference an identifier before its definition ; in module: ",,,test.rkt"


laurent.orseau
2022-5-4 10:33:11

You need the struct name of the parent: (sup-fld1 S)


jgeddes
2022-5-4 10:33:34

Oh!


jgeddes
2022-5-4 10:33:53

Is that how that’s always worked?


jgeddes
2022-5-4 10:35:45

Well, anyway, thanks so much. That certainly answers my question!


laurent.orseau
2022-5-4 10:42:24

yes :slightly_smiling_face:


spdegabrielle
2022-5-4 11:59:22

:point_up_2:this would be a great ‘today I learnt’ to share with others via the Racket Discourse: https://racket.discourse.group/tag/today-i-learnt


spdegabrielle
2022-5-4 12:13:18

Reminder the Racket meet-up is Saturday 18:00 UTC

I can’t attend as I will be at my local music festival so have fun


jgeddes
2022-5-4 13:10:24

Done, I think!


spdegabrielle
2022-5-4 13:12:02

Awesome! Thank you!


massung
2022-5-4 13:58:50

May the Fourth be with you all today. And in the spirit of such a grand day, I shall leave you with a nice little joke:

Q: What is the internal temperature of a Tauntaun? A: Lukewarm

https://media.giphy.com/media/3ornjSL2sBcPflIDiU/giphy.gif


laurent.orseau
2022-5-4 15:06:43

Do I get this right: lambdas not attached to a define tend to prevent a number of optimizations, e.g. inlining?


massung
2022-5-4 15:16:35

By definition a closure (with lexical context) can’t be inlined because it’s created at runtime.


massung
2022-5-4 15:18:29

So, that optimization is out the window. There are probably others as well: folding for knowably immutable+constant values, probably various detections of short-lived objects for GC would be another.


sorawee
2022-5-4 15:24:38

Also, lambda with keyword argument not attached to define can’t be inlined.


sorawee
2022-5-4 15:24:53

> For direct calls to functions with keyword arguments, the compiler can typically check keyword arguments statically and generate a direct call to a non-keyword variant of the function, which reduces the run-time overhead of keyword checking. This optimization applies only for keyword-accepting procedures that are bound with define.



ryanc
2022-5-4 18:27:28

@laurent.orseau and @massung: “tend to”, but not always. For example, if you start Racket CS with PLT_LINKLET_SHOW_CP0=1 racket and evaluate this code: (lambda (xs) (and (list? xs) (map (lambda (n) (+ n 1)) xs))), you’ll see that after “cp0” (which, IIRC, does inlining and other high-level optimizations), both map and the inner lambda have been inlined away. In the cp0 version, I think only the outer lambdas will result in closure allocations; I think the letrec-bound lambda will just turn into a label for direct calls.


massung
2022-5-4 18:30:17

In that example it’s not a closure with lexical context though. It’s just a function that takes a single argument that can be globally defined and called.


sorawee
2022-5-4 18:32:10

Btw, https://docs.racket-lang.org/loop/index.html#%28part._.Performance%29 is a concrete example where the inlining fails.


ryanc
2022-5-4 18:37:17

Try (lambda (xs c) (and (list? xs) (map (lambda (n) (+ n c)) xs))) or (lambda (xs) (and (list? xs) (map (let ([c 1]) (lambda (n) (+ n c))) xs))). In both cases, the inner lambda has free variables (what you’re calling a “closure”, I think), but it still gets inlined away. (A closure is one implementation strategy for lambda, but the compiler decides whether a lambda expression needs to be represented as a closure. So it doesn’t make sense to say that the compiler can’t inline closures. You could claim that the compiler cannot inline lambda expressions with free variables, but that is wrong; see the examples above.)


laurent.orseau
2022-5-4 18:58:05

Quite informative, thanks!


massung
2022-5-4 20:02:57

@ryanc - makes sense. Perhaps more qualifying is that it can’t inline lambda expressions with free variables outside the scope they are declared in?


massung
2022-5-4 20:03:57

For example, there’s no world I can envision in which map could inline a function passed to it. It might be possible to inline map itself with an inlined version of the supplied function, though.