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

From: Matthias Felleisen (matthias at ccs.neu.edu)
Date: Thu Jun 5 21:13:47 EDT 2014

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

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20140605/fd73f53a/attachment.html>

Posted on the users mailing list.