Re: [racket-users] struct-info

2019-02-12 Thread David Storrs
Thanks Matthias, that makes sense.

On Tue, Feb 12, 2019 at 8:50 PM Matthias Felleisen
 wrote:
>
>
>
> > On Feb 12, 2019, at 5:28 PM, David Storrs  wrote:
> >
> > On Tue, Feb 12, 2019 at 5:03 PM  wrote:
> 
>  This is nice for defining abstract types, but it can be pretty 
>  inconvenient for defining plain old aggregated data types that just have 
>  a bundle of fields. When defining those types as structs, consider using 
>  the #:transparent option. This means "use no inspector at all" (roughly) 
>  and lets `struct-info` Just Work (TM) without any inspector wrangling. 
>  The downside is that other modules may be able to break your type's 
>  invariants and possibly circumvent your contracts.
> >>>
> >>>
> >>> That's what I expected, but it doesn't seem to work:
> >>>
>  (struct person (name age) #:transparent)
>  (struct-info person)
> >>> #f
> >>> #t
> >>>
> >>> What am I missing?
> >>
> >>
> >> I was stumped on this for a while, but then realized the problem:
> >>
> >>> (struct-info person)
> >> #f
> >> #t
> >>> (struct-info (person "Alyssa P. Hacker" 42))
> >> #
> >> #f
> >
> > Ah, I see.  Thanks, I wouldn't have guessed that an instance of a
> > struct satisfied `struct-type?`
> >
> > On the other hand, it seems relatively easy to break these
> > protections.  Is there a way to prevent that?
> >
> > ; file test1.rkt
> > #lang racket
> > (struct person (name age))
> > (provide person)
>
>
>
> The line above exports two pieces: the constructor and compile-time 
> information about the structure, including the functions as you saw. If you 
> want to protect your invariants, you replace this provide with something like
>
>(provide (contract-out (person (-> string natural-number/c person?
>
> See end for a simpler way to test such things.
>
>
>
> > ;; end of test1.rkt
> >
> >
> > ; file test2.rkt
> > #lang racket
> >
> > (require "test1.rkt"
> > (for-syntax racket
> > syntax/parse
> > syntax/parse/experimental/template
> > syntax/parse/class/struct-id))
> >
> > (define p (person 'bob 19))
> > (displayln "required ctor only of a struct defined in another file.
> > Can create, is opaque:")
> > p
> > (displayln "struct-info returns (values #f #t) since the struct isn't
> > inspectable here:")
> > (struct-info p)
> > (define-syntax struct-funcs (syntax-parser [(_ s:struct-id) (template
> > (list s.constructor-id s.accessor-id ...))]))
> > (define lst (struct-funcs person))
> > (displayln "show list of constructor and accessors that we retrieved
> > via macro:")
> > lst
> > (displayln "Fetch name ('bob) by way of accessor returned through macro:")
> > ((second lst) p)
> > ; Uncommenting the following will cause compilation to fail, since
> > person-name was not exported
> > ;(person-name p)
> > ;;  end of test2.rkt
> >
> >
> > ;; command line:
> > $ racket test2.rkt
> > required ctor only of a struct defined in another file. Can create, is 
> > opaque:
> > #
> > struct-info returns (values #f #t) since the struct isn't inspectable here:
> > #f
> > #t
> > show list of constructor and accessors that we retrieved via macro:
> > '(# # #)
> > Fetch name ('bob) by way of accessor returned through macro:
> > 'bob
> >
> > -
>
>
>
>
> #lang racket
>
> (module test1 racket
>   (provide (contract-out (person (-> string natural-number/c person?
>   (struct person (name age)))
>
> (module test2 racket
>   (require (submod ".." test1)
>(for-syntax racket
>syntax/parse
>syntax/parse/experimental/template
>syntax/parse/class/struct-id))
>
>   (define p (person 'bob 19))
>   (displayln "required ctor only of a struct defined in another file. Can 
> create, is opaque:")
>   p
>
>   (displayln "struct-info returns (values #f #t) since the struct isn't 
> inspectable here:")
>   (struct-info p)
>
>   (define-syntax struct-funcs (syntax-parser [(_ s:struct-id) (template (list 
> s.constructor-id s.accessor-id ...))]))
>   (define lst (struct-funcs person))
>   (displayln "show list of constructor and accessors that we retrieved via 
> macro:")
>   lst
>
>   (displayln "Fetch name ('bob) by way of accessor returned through macro:")
>   ((second lst) p)
>
>   ; Uncommenting the following will cause compilation to fail, since
>   ; person-name
>   )
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] struct-info

2019-02-12 Thread Matthias Felleisen



> On Feb 12, 2019, at 5:28 PM, David Storrs  wrote:
> 
> On Tue, Feb 12, 2019 at 5:03 PM  wrote:
 
 This is nice for defining abstract types, but it can be pretty 
 inconvenient for defining plain old aggregated data types that just have a 
 bundle of fields. When defining those types as structs, consider using the 
 #:transparent option. This means "use no inspector at all" (roughly) and 
 lets `struct-info` Just Work (TM) without any inspector wrangling. The 
 downside is that other modules may be able to break your type's invariants 
 and possibly circumvent your contracts.
>>> 
>>> 
>>> That's what I expected, but it doesn't seem to work:
>>> 
 (struct person (name age) #:transparent)
 (struct-info person)
>>> #f
>>> #t
>>> 
>>> What am I missing?
>> 
>> 
>> I was stumped on this for a while, but then realized the problem:
>> 
>>> (struct-info person)
>> #f
>> #t
>>> (struct-info (person "Alyssa P. Hacker" 42))
>> #
>> #f
> 
> Ah, I see.  Thanks, I wouldn't have guessed that an instance of a
> struct satisfied `struct-type?`
> 
> On the other hand, it seems relatively easy to break these
> protections.  Is there a way to prevent that?
> 
> ; file test1.rkt
> #lang racket
> (struct person (name age))
> (provide person)



The line above exports two pieces: the constructor and compile-time information 
about the structure, including the functions as you saw. If you want to protect 
your invariants, you replace this provide with something like 

   (provide (contract-out (person (-> string natural-number/c person?

See end for a simpler way to test such things. 



> ;; end of test1.rkt
> 
> 
> ; file test2.rkt
> #lang racket
> 
> (require "test1.rkt"
> (for-syntax racket
> syntax/parse
> syntax/parse/experimental/template
> syntax/parse/class/struct-id))
> 
> (define p (person 'bob 19))
> (displayln "required ctor only of a struct defined in another file.
> Can create, is opaque:")
> p
> (displayln "struct-info returns (values #f #t) since the struct isn't
> inspectable here:")
> (struct-info p)
> (define-syntax struct-funcs (syntax-parser [(_ s:struct-id) (template
> (list s.constructor-id s.accessor-id ...))]))
> (define lst (struct-funcs person))
> (displayln "show list of constructor and accessors that we retrieved
> via macro:")
> lst
> (displayln "Fetch name ('bob) by way of accessor returned through macro:")
> ((second lst) p)
> ; Uncommenting the following will cause compilation to fail, since
> person-name was not exported
> ;(person-name p)
> ;;  end of test2.rkt
> 
> 
> ;; command line:
> $ racket test2.rkt
> required ctor only of a struct defined in another file. Can create, is opaque:
> #
> struct-info returns (values #f #t) since the struct isn't inspectable here:
> #f
> #t
> show list of constructor and accessors that we retrieved via macro:
> '(# # #)
> Fetch name ('bob) by way of accessor returned through macro:
> 'bob
> 
> -




#lang racket

(module test1 racket
  (provide (contract-out (person (-> string natural-number/c person?
  (struct person (name age)))

(module test2 racket 
  (require (submod ".." test1)
   (for-syntax racket
   syntax/parse
   syntax/parse/experimental/template
   syntax/parse/class/struct-id))

  (define p (person 'bob 19))
  (displayln "required ctor only of a struct defined in another file. Can 
create, is opaque:")
  p
  
  (displayln "struct-info returns (values #f #t) since the struct isn't 
inspectable here:")
  (struct-info p)

  (define-syntax struct-funcs (syntax-parser [(_ s:struct-id) (template (list 
s.constructor-id s.accessor-id ...))]))
  (define lst (struct-funcs person))
  (displayln "show list of constructor and accessors that we retrieved via 
macro:")
  lst
  
  (displayln "Fetch name ('bob) by way of accessor returned through macro:")
  ((second lst) p)

  ; Uncommenting the following will cause compilation to fail, since
  ; person-name
  )

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] struct-info

2019-02-12 Thread David Storrs
On Tue, Feb 12, 2019 at 5:03 PM  wrote:
>>>
>>> This is nice for defining abstract types, but it can be pretty inconvenient 
>>> for defining plain old aggregated data types that just have a bundle of 
>>> fields. When defining those types as structs, consider using the 
>>> #:transparent option. This means "use no inspector at all" (roughly) and 
>>> lets `struct-info` Just Work (TM) without any inspector wrangling. The 
>>> downside is that other modules may be able to break your type's invariants 
>>> and possibly circumvent your contracts.
>>
>>
>> That's what I expected, but it doesn't seem to work:
>>
>> > (struct person (name age) #:transparent)
>> > (struct-info person)
>> #f
>> #t
>>
>> What am I missing?
>
>
> I was stumped on this for a while, but then realized the problem:
>
> > (struct-info person)
> #f
> #t
> > (struct-info (person "Alyssa P. Hacker" 42))
> #
> #f

Ah, I see.  Thanks, I wouldn't have guessed that an instance of a
struct satisfied `struct-type?`

On the other hand, it seems relatively easy to break these
protections.  Is there a way to prevent that?

; file test1.rkt
#lang racket
(struct person (name age))
(provide person)
;; end of test1.rkt


; file test2.rkt
#lang racket

(require "test1.rkt"
 (for-syntax racket
 syntax/parse
 syntax/parse/experimental/template
 syntax/parse/class/struct-id))

(define p (person 'bob 19))
(displayln "required ctor only of a struct defined in another file.
Can create, is opaque:")
p
(displayln "struct-info returns (values #f #t) since the struct isn't
inspectable here:")
(struct-info p)
(define-syntax struct-funcs (syntax-parser [(_ s:struct-id) (template
(list s.constructor-id s.accessor-id ...))]))
(define lst (struct-funcs person))
(displayln "show list of constructor and accessors that we retrieved
via macro:")
lst
(displayln "Fetch name ('bob) by way of accessor returned through macro:")
((second lst) p)
; Uncommenting the following will cause compilation to fail, since
person-name was not exported
;(person-name p)
;;  end of test2.rkt


;; command line:
$ racket test2.rkt
required ctor only of a struct defined in another file. Can create, is opaque:
#
struct-info returns (values #f #t) since the struct isn't inspectable here:
#f
#t
show list of constructor and accessors that we retrieved via macro:
'(# # #)
Fetch name ('bob) by way of accessor returned through macro:
'bob

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] struct-info

2019-02-12 Thread Shu-Hung You
On Tue, Feb 12, 2019 at 3:55 PM David Storrs  wrote:
>
> On Tue, Feb 12, 2019 at 4:46 PM  wrote:
> >>
> >> Thank you for the explanation.  Can I ask why the heck it works this
> >> way?  This seems to be explicitly designed for maximal surprise and
> >> minimal usefulness.
> >
> >
> > It works that way so that, by default, modules can't inspect, modify, or 
> > otherwise muck around with structs defined by other modules. Opaque structs 
> > (that is, structs that aren't transparent and aren't prefab) aren't really 
> > meant to be used like "plain old data objects" with fields and accessors, 
> > they're more like building blocks for abstract data types. A module that 
> > defines an opaque struct type is expected to be responsible for exporting 
> > to other modules all the functions that are necessary for using that type. 
> > Anything not explicitly exported by the module is not allowed, even through 
> > reflective operations like struct-info. The exception to this rule is when 
> > some entity above the modules is controlling them all, such as a debugger, 
> > an IDE, or a server running client-supplied code. In these cases, the 
> > controlling code has the option to make a child inspector and run all the 
> > modules under that child inspector, giving the controlling code access to 
> > all struct types through the parent inspector. This kind of setup can be 
> > nested arbitrarily deep.
>
> I see.  That makes sense.  I think it would be worth expanding the
> documentation on that; I'm happy to provide a suggestion later
> tonight, but I will need to do it through email instead of via pull
> request.  I have long since given up on being able to find anything in
> the Racket github in order to provide patches.  It's simply too
> unintuitive and time-intensive to find the relevant section in
> multiple repositories where the documentation is in randomly-named
> fragments scattered across multiple directories instead of being
> individual files with guessable names.
>
>
> >
> > This is nice for defining abstract types, but it can be pretty inconvenient 
> > for defining plain old aggregated data types that just have a bundle of 
> > fields. When defining those types as structs, consider using the 
> > #:transparent option. This means "use no inspector at all" (roughly) and 
> > lets `struct-info` Just Work (TM) without any inspector wrangling. The 
> > downside is that other modules may be able to break your type's invariants 
> > and possibly circumvent your contracts.
>
> That's what I expected, but it doesn't seem to work:
>
> > (struct person (name age) #:transparent)
> > (struct-info person)
> #f
> #t
>
> What am I missing?
>

It takes an instance of person.

(struct-info (person "Me" 3.14))

FWIW if you already have the struct type descriptor (which is what
struct-info returns), you can directly call struct-type-info.

(struct-type-info
 (let-values ([(desc skip?) (struct-info (person "Me" 3.14))])
   desc))

;; struct:person is introduced by the (struct person ...) form
(struct-type-info struct:person)

> --
> You received this message because you are subscribed to the Google Groups 
> "Racket Users" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to racket-users+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] struct-info

2019-02-12 Thread jackhfirth

>
> This is nice for defining abstract types, but it can be pretty 
>> inconvenient for defining plain old aggregated data types that just have a 
>> bundle of fields. When defining those types as structs, consider using the 
>> #:transparent option. This means "use no inspector at all" (roughly) and 
>> lets `struct-info` Just Work (TM) without any inspector wrangling. The 
>> downside is that other modules may be able to break your type's invariants 
>> and possibly circumvent your contracts. 
>
>
> That's what I expected, but it doesn't seem to work: 
>
> > (struct person (name age) #:transparent) 
> > (struct-info person) 
> #f 
> #t 
>
> What am I missing?
>

I was stumped on this for a while, but then realized the problem:

> (struct-info person)
#f
#t
> (struct-info (person "Alyssa P. Hacker" 42))
#
#f

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] struct-info

2019-02-12 Thread David Storrs
On Tue, Feb 12, 2019 at 4:46 PM  wrote:
>>
>> Thank you for the explanation.  Can I ask why the heck it works this
>> way?  This seems to be explicitly designed for maximal surprise and
>> minimal usefulness.
>
>
> It works that way so that, by default, modules can't inspect, modify, or 
> otherwise muck around with structs defined by other modules. Opaque structs 
> (that is, structs that aren't transparent and aren't prefab) aren't really 
> meant to be used like "plain old data objects" with fields and accessors, 
> they're more like building blocks for abstract data types. A module that 
> defines an opaque struct type is expected to be responsible for exporting to 
> other modules all the functions that are necessary for using that type. 
> Anything not explicitly exported by the module is not allowed, even through 
> reflective operations like struct-info. The exception to this rule is when 
> some entity above the modules is controlling them all, such as a debugger, an 
> IDE, or a server running client-supplied code. In these cases, the 
> controlling code has the option to make a child inspector and run all the 
> modules under that child inspector, giving the controlling code access to all 
> struct types through the parent inspector. This kind of setup can be nested 
> arbitrarily deep.

I see.  That makes sense.  I think it would be worth expanding the
documentation on that; I'm happy to provide a suggestion later
tonight, but I will need to do it through email instead of via pull
request.  I have long since given up on being able to find anything in
the Racket github in order to provide patches.  It's simply too
unintuitive and time-intensive to find the relevant section in
multiple repositories where the documentation is in randomly-named
fragments scattered across multiple directories instead of being
individual files with guessable names.


>
> This is nice for defining abstract types, but it can be pretty inconvenient 
> for defining plain old aggregated data types that just have a bundle of 
> fields. When defining those types as structs, consider using the 
> #:transparent option. This means "use no inspector at all" (roughly) and lets 
> `struct-info` Just Work (TM) without any inspector wrangling. The downside is 
> that other modules may be able to break your type's invariants and possibly 
> circumvent your contracts.

That's what I expected, but it doesn't seem to work:

> (struct person (name age) #:transparent)
> (struct-info person)
#f
#t

What am I missing?

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] struct-info

2019-02-12 Thread jackhfirth

>
> Thank you for the explanation.  Can I ask why the heck it works this 
> way?  This seems to be explicitly designed for maximal surprise and 
> minimal usefulness. 
>

It works that way so that, by default, modules can't inspect, modify, or 
otherwise muck around with structs defined by other modules. Opaque structs 
(that is, structs that aren't transparent and aren't prefab) aren't really 
meant to be used like "plain old data objects" with fields and accessors, 
they're more like building blocks for abstract data types. A module that 
defines an opaque struct type is expected to be responsible for exporting 
to other modules all the functions that are necessary for using that type. 
Anything not explicitly exported by the module is not allowed, even through 
reflective operations like struct-info. The exception to this rule is when 
some entity *above* the modules is controlling them all, such as a 
debugger, an IDE, or a server running client-supplied code. In these cases, 
the controlling code has the option to make a child inspector and run all 
the modules under that child inspector, giving the controlling code access 
to all struct types through the parent inspector. This kind of setup can be 
nested arbitrarily deep.

This is nice for defining abstract types, but it can be pretty inconvenient 
for defining plain old aggregated data types that just have a bundle of 
fields. When defining those types as structs, consider using the 
#:transparent option. This means "use no inspector at all" (roughly) and 
lets `struct-info` Just Work (TM) without any inspector wrangling. The 
downside is that other modules may be able to break your type's invariants 
and possibly circumvent your contracts.

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] struct-info

2019-02-12 Thread David Storrs
On Tue, Feb 12, 2019 at 11:43 AM Shu-Hung You
 wrote:
>
> On Tue, Feb 12, 2019 at 10:04 AM David Storrs  wrote:
> >
> > Could someone point me to the FM on how to properly use struct-info?
> > For the life of me, I cannot get anything except (values #f #t) out of
> > it.  I see that:
> >
> > 1) struct-info only works with struct types that are under the control
> > of the current inspector.
> >
> > 2) You can provide an inspector to a struct declaration, but it will
> > be placed under the control of the **parent** of what you passed it,
> > not the actual thing you passed it.  This breaks my brain.
> >
>
> The inspector used at struct type creation time needs to be controlled
> by the current inspector so you can obtain reflective information.
> That is, the inspector used at struct type creation time is a
> sub(-sub-sub-...) inspector of the current inspector.
>
> #lang racket/base
>
> (require racket/struct-info)
>
> (define old-insp (current-inspector))
> (define insp (make-inspector))
>
> (current-inspector insp)
> (struct S (field1 field2))
> (current-inspector old-insp)
>
> (define s
>   (S 5 'hi))
>
> (struct-info s) ;;=> ok
>
> (current-inspector insp)
> (struct-info s) ;;=> #f #t

Thank you for the explanation.  Can I ask why the heck it works this
way?  This seems to be explicitly designed for maximal surprise and
minimal usefulness.


>
>
> > --
> > You received this message because you are subscribed to the Google Groups 
> > "Racket Users" group.
> > To unsubscribe from this group and stop receiving emails from it, send an 
> > email to racket-users+unsubscr...@googlegroups.com.
> > For more options, visit https://groups.google.com/d/optout.

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] struct-info

2019-02-12 Thread Shu-Hung You
On Tue, Feb 12, 2019 at 10:04 AM David Storrs  wrote:
>
> Could someone point me to the FM on how to properly use struct-info?
> For the life of me, I cannot get anything except (values #f #t) out of
> it.  I see that:
>
> 1) struct-info only works with struct types that are under the control
> of the current inspector.
>
> 2) You can provide an inspector to a struct declaration, but it will
> be placed under the control of the **parent** of what you passed it,
> not the actual thing you passed it.  This breaks my brain.
>

The inspector used at struct type creation time needs to be controlled
by the current inspector so you can obtain reflective information.
That is, the inspector used at struct type creation time is a
sub(-sub-sub-...) inspector of the current inspector.

#lang racket/base

(require racket/struct-info)

(define old-insp (current-inspector))
(define insp (make-inspector))

(current-inspector insp)
(struct S (field1 field2))
(current-inspector old-insp)

(define s
  (S 5 'hi))

(struct-info s) ;;=> ok

(current-inspector insp)
(struct-info s) ;;=> #f #t


> --
> You received this message because you are subscribed to the Google Groups 
> "Racket Users" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to racket-users+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[racket-users] struct-info

2019-02-12 Thread David Storrs
Could someone point me to the FM on how to properly use struct-info?
For the life of me, I cannot get anything except (values #f #t) out of
it.  I see that:

1) struct-info only works with struct types that are under the control
of the current inspector.

2) You can provide an inspector to a struct declaration, but it will
be placed under the control of the **parent** of what you passed it,
not the actual thing you passed it.  This breaks my brain.

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.