[racket] How to get arity of make-object?

From: Robby Findler (robby at eecs.northwestern.edu)
Date: Fri Jun 6 12:06:42 EDT 2014

What is wrong with this?

Robby

On Thu, Jun 5, 2014 at 8:13 PM, Matthias Felleisen <matthias at ccs.neu.edu> wrote:
>
> class/c doesn't check inits properly:
>
> #lang racket
>
> (provide
>   (contract-out
>     [c% (class/c (init-field [x number?]))]))
>
> (define c%
>   (class object%
>     (field (x 10))
>     (super-new)))
>
>
> and now run
>
> Welcome to Racket v6.0.1.12.
>> (require "foo.rkt")
>> (new c%)
> (object:c% ...)
>
>
> Okay more thinking to do -- Matthias
>
>
>
>
> On Jun 5, 2014, at 8:49 PM, Roman Klochkov wrote:
>
> It is maybe closer.
>
> But inside define-binary-class I also doesn't know the total number of init
> arguments. Because library user may give any superclass. And I don't know,
> how to get init arguments (or arity for of make-object for a given class)
> without calling make-object and reading the error message.
> Lake in case
> (define base% (class (super-new) (init-field param1 param2)))
> (define-binary-class db base% ((a u1) (b u2)))
>
> Maybe the problem doesn't have a solution. But I see class/c, which has init
> and init-fields clauses. Somehow it checks them...
>
> Thu, 5 Jun 2014 16:36:16 -0400 от Matthias Felleisen <matthias at ccs.neu.edu>:
>
>
> Sorry I am so slow.
>
> Contracts are first-class values.
>
> You could modify define-binary-class so that it also creates and defines
> a contract P that can be passed along to read-object. Then read-object
> can use P like this:
>
>> #lang racket
>>
>> (provide
>> a% a?
>> b% b?
>> (contract-out
>> (read-object (->i ((c? contract?) (c% any/c))
>> #:rest [l (c?) (lambda (x) (apply c? x))]
>> (_ (c%) (is-a?/c c%))))))
>>
>> (define a% (class object% [init-field x] (super-new)))
>> (define b% (class object% [init-field x y] (super-new)))
>>
>> (define a? (lambda x (and (= (length x) 1) (andmap number? x))))
>> (define b? (lambda x (and (= (length x) 2) (andmap number? x))))
>>
>> (define (read-object __c c% . x)
>> (apply make-object c% x))
>
> Then you get exactly what you want and pretty precise checking:
>
>> % !!
>> racket
>> Welcome to Racket v6.0.1.11.
>> > (require "foo.rkt")
>> foo.rkt:9:23: is-a/c?: unbound identifier in module
>> in: is-a/c?
>> context...:
>> standard-module-name-resolver
>> /Users/matthias/plt/racket/collects/racket/private/misc.rkt:87:7
>> > (require "foo.rkt")
>> foo.rkt:9:31: c%: unbound identifier in module
>> in: c%
>> context...:
>> standard-module-name-resolver
>> /Users/matthias/plt/racket/collects/racket/private/misc.rkt:87:7
>> > (require "foo.rkt")
>> > ( read-object b? b% 10 20 )
>> (object:b% ...)
>> > ( read-object b? b% 10 )
>> read-object: contract violation
>> expected: ...vn/2HtDP/foo.rkt:8:34
>> given: '(10)
>> in: the l argument of
>> (->i
>> ((c? contract?) (c% any/c))
>> #:rest
>> (l (c?) (lambda (x) (apply c? x)))
>> (_ (c%) (is-a?/c c%)))
>> contract from:
>> /Users/matthias/svn/2HtDP/foo.rkt
>> blaming: top-level
>> at: /Users/matthias/svn/2HtDP/foo.rkt:7.5
>> context...:
>>
>> /Users/matthias/plt/racket/collects/racket/contract/private/blame.rkt:143:0:
>> raise-blame-error16
>> arg-checker
>> /Users/matthias/plt/racket/collects/racket/private/misc.rkt:87:7
>> > ( read-object a? a% 10 )
>> (object:a% ...)
>> > ( read-object a? a% 10 20)
>> read-object: contract violation
>> expected: ...vn/2HtDP/foo.rkt:8:34
>> given: '(10 20)
>> in: the l argument of
>> (->i
>> ((c? contract?) (c% any/c))
>> #:rest
>> (l (c?) (lambda (x) (apply c? x)))
>> (_ (c%) (is-a?/c c%)))
>> contract from:
>> /Users/matthias/svn/2HtDP/foo.rkt
>> blaming: top-level
>> at: /Users/matthias/svn/2HtDP/foo.rkt:7.5
>> context...:
>>
>> /Users/matthias/plt/racket/collects/racket/contract/private/blame.rkt:143:0:
>> raise-blame-error16
>> arg-checker
>> /Users/matthias/plt/racket/collects/racket/private/misc.rkt:87:7
>
>
>
> If you want to make sure that a? and a% come together, you can package them
> up in structs.
>
> If you just want to make sure that these contracts come from your binary
> class module, you can hide them in applicable structs or something like
> that.
>
> Am I getting closer? -- Matthias
>
>
>
>
> On Jun 5, 2014, at 4:15 PM, Roman Klochkov <kalimehtar at mail.ru> wrote:
>
>> I don't create classes. I provide a function read-object, so user can do
>>
>> (require binary-class)
>> (define base% (class (super-new) (init-field param1 param2)))
>> (define-binary-class db base% ((a u1) (b u2)))
>>
>> (define data (read-object db my-file data-param1 data-param2)
>>
>> And I try to make a contract, so when he made an error in last call and
>> wrote
>>
>> (define data (read-object db my-file data-param1)), then error message
>> whould blame read-object, not `instantiate'
>>
>> Thu, 5 Jun 2014 16:08:39 -0400 от Matthias Felleisen
>> <matthias at ccs.neu.edu>:
>>
>> Can't you use is-a?/c like this:
>>
>> > #lang racket
>> >
>> > (provide
>> > a%
>> > b%
>> > (contract-out
>> > (read-object (case->
>> > [-> (is-a?/c a%) number? number?]
>> > [-> (is-a?/c b%) number? number? number?]))))
>> >
>> > (define a% (class object% (super-new)))
>> > (define b% (class object% (super-new)))
>> >
>> > (define read-object
>> > (case-lambda
>> > [(a x) x]
>> > [(b x y) (+ x y)]))
>>
>>
>> and use this module like this:
>>
>> > % racket
>> > Welcome to Racket v6.0.1.11.
>> > > (require "foo.rkt")
>> > > (read-object (new a%) 10)
>> > 10
>> > > (read-object (new a%) 10 20)
>> > read-object: contract violation
>> > expected: (is-a?/c b%)
>> > given: (object:a% ...)
>> > in: the domain of
>> > the 2nd case of
>> > (case->
>> > (-> (is-a?/c a%) number? number?)
>> > (-> (is-a?/c b%) number? number? number?))
>> > contract from:
>> > /Users/matthias/svn/2HtDP/foo.rkt
>> > blaming: top-level
>> > at: /Users/matthias/svn/2HtDP/foo.rkt:7.5
>> > context...:
>> >
>> > /Users/matthias/plt/racket/collects/racket/contract/private/blame.rkt:143:0:
>> > raise-blame-error16
>> > /Users/matthias/plt/racket/collects/racket/private/misc.rkt:87:7
>> > > (read-object (new b%) 10 20)
>> > 30
>> > > (read-object (new b%) 10)
>> > read-object: contract violation
>> > expected: (is-a?/c a%)
>> > given: (object:b% ...)
>> > in: the domain of
>> > the 1st case of
>> > (case->
>> > (-> (is-a?/c a%) number? number?)
>> > (-> (is-a?/c b%) number? number? number?))
>> > contract from:
>> > /Users/matthias/svn/2HtDP/foo.rkt
>> > blaming: top-level
>> > at: /Users/matthias/svn/2HtDP/foo.rkt:7.5
>> > context...:
>> >
>> > /Users/matthias/plt/racket/collects/racket/contract/private/blame.rkt:143:0:
>> > raise-blame-error16
>> > /Users/matthias/plt/racket/collects/racket/private/misc.rkt:87:7
>>
>>
>>
>> On Jun 5, 2014, at 3:19 PM, Roman Klochkov <kalimehtar at mail.ru> wrote:
>>
>> > (define (read-object binary-class in . args)
>> > (send (apply make-object binary-class args) read in))
>> >
>> > read-object takes a class as a first arg, and additional arguments to
>> > make an object of that class.
>> >
>> > I can't make case-> because I don't know j,ject of what (user-defined)
>> > class will be created with the function by user of my library.
>> >
>> > This case is described in Racket Guide 7,3.9
>> > http://docs.racket-lang.org/guide/contracts-general-functions.html#%28part._contracts-no-domain%29
>> > , where recommended to use unconstrained-domain-> with
>> > procedure-arity-includes? , but it doesnt' work with make-object
>> >
>> > Thu, 5 Jun 2014 14:51:21 -0400 от Matthias Felleisen
>> > <matthias at ccs.neu.edu>:
>> >
>> > From what I understand now, you want a contract for a function that
>> > creates objects from a variable number of arguments. If you write your
>> > module interface like this,
>> >
>> > > #lang racket
>> > >
>> > > (provide
>> > > (contract-out
>> > > (read-object (case->
>> > > [-> 'a number? number?]
>> > > [-> 'b number? number? number?]))))
>> > >
>> > > (define read-object
>> > > (case-lambda
>> > > [(a x) x]
>> > > [(b x y) (+ x y)]))
>> >
>> > you can get checked variable-arity behavior:
>> >
>> > > Welcome to Racket v6.0.1.11.
>> > > > (require "foo.rkt")
>> > > > (read-object 'a 10)
>> > > 10
>> > > > (read-object 'b 10 20)
>> > > 30
>> > > > (read-object 'b 10)
>> > > read-object: contract violation
>> > > expected: (quote a)
>> > > given: 'b
>> > > in: the domain of
>> > > the 1st case of
>> > > (case->
>> > > (-> 'a number? number?)
>> > > (-> 'b number? number? number?))
>> > > contract from:
>> > > /Users/matthias/svn/2HtDP/foo.rkt
>> > > blaming: top-level
>> > > at: /Users/matthias/svn/2HtDP/foo.rkt:5.5
>> > > context...:
>> > >
>> > > /Users/matthias/plt/racket/collects/racket/contract/private/blame.rkt:143:0:
>> > > raise-blame-error16
>> > > /Users/matthias/plt/racket/collects/racket/private/misc.rkt:87:7
>> > > > (read-object 'a 10 20)
>> > > read-object: contract violation
>> > > expected: (quote b)
>> > > given: 'a
>> > > in: the domain of
>> > > the 2nd case of
>> > > (case->
>> > > (-> 'a number? number?)
>> > > (-> 'b number? number? number?))
>> > > contract from:
>> > > /Users/matthias/svn/2HtDP/foo.rkt
>> > > blaming: top-level
>> > > at: /Users/matthias/svn/2HtDP/foo.rkt:5.5
>> > > context...:
>> > >
>> > > /Users/matthias/plt/racket/collects/racket/contract/private/blame.rkt:143:0:
>> > > raise-blame-error16
>> > > /Users/matthias/plt/racket/collects/racket/private/misc.rkt:87:7
>> >
>> >
>> > I think you can use ->i contracts inside of the case-> clauses if you
>> > need more precision.
>> >
>> > If I am still misunderstanding your question, sorry.
>> >
>> > -- Matthias
>> >
>> >
>> >
>> >
>> > > >
>> > > >
>> > > > --
>> > > > Roman Klochkov
>> > >
>> > >
>> > >
>> > > --
>> > > Roman Klochkov
>> >
>> >
>> >
>> > --
>> > Roman Klochkov
>>
>>
>>
>> --
>> Roman Klochkov
>
>
>
> --
> Roman Klochkov
>
>
>
> ____________________
>   Racket Users list:
>   http://lists.racket-lang.org/users
>


Posted on the users mailing list.