[racket] How to get arity of make-object?
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
> >
> >
> >
> >
> >
> > On Jun 5, 2014, at 1:41 PM, Roman Klochkov <kalimehtar at mail.ru> wrote:
> >
> > > It is not writing, but reading. I'm making uinversal library for binary data (like dbf, mp3 id3 tags, and so on) mapping to objects
> > > https://github.com/Kalimehtar/binary-class
> > >
> > > read-object simply
> > >
> > > (define (read-object binary-class in . args)
> > > (send (apply make-object binary-class args) read in))
> > >
> > > But I don't like, that contract may not give correct error message for wrong nomber of items in args.
> > >
> > >
> > > Thu, 5 Jun 2014 12:31:49 -0400 от Matthias Felleisen <matthias at ccs.neu.edu>:
> > >
> > > Do you control the writing of objects to a port? If so, check out 'serialization.' If not, I don't think I can help you. Sorry -- Matthias
> > >
> > >
> > >
> > > On Jun 5, 2014, at 12:29 PM, Roman Klochkov <kalimehtar at mail.ru> wrote:
> > >
> > > > I don't control class creation.
> > > > I need to make a wrapper around make-object and attach contract to the wrapper.
> > > >
> > > > Now I have
> > > > (provide/contract
> > > > [read-object (->i ([binary-class (implementation?/c binary<%>)]
> > > > [port input-port?])
> > > > #:rest [args list?]
> > > > [result (binary-class) (is-a?/c binary-class)])])
> > > >
> > > > I cannot control number of args. Now, when error encountered I have confusing error message mentioning "instantiate".
> > > >
> > > > Thu, 5 Jun 2014 12:13:26 -0400 от Matthias Felleisen <matthias at ccs.neu.edu>:
> > > >
> > > > Here is the pattern I recommend:
> > > >
> > > > Welcome to Racket v6.0.1.11.
> > > > > (define (create-c #:x [x 0]) (new c% [x x]))
> > > > > (define c% (class object% (init-field x) (super-new)))
> > > >
> > > > That is, a class comes with a 'factory' definition, a function that creates instances and uses keywords similar to those used by the class initializer. If you then export these factories, you can enforce invariants and also probe the factory for the information you want:
> > > >
> > > > > (create-c)
> > > > (object:c% ...)
> > > > > (create-c #:x 10)
> > > > (object:c% ...)
> > > > > (procedure-arity create-c)
> > > > 0
> > > > > (procedure-keywords create-c)
> > > > '()
> > > > '(#:x)
> > > >
> > > >
> > > > Yes, one could argue that this is a poor man's substitute for missing class reflection. -- Matthias
> > > >
> > > >
> > > >
> > > >
> > > >
> > > >
> > > > On Jun 5, 2014, at 11:32 AM, Roman Klochkov <kalimehtar at mail.ru> wrote:
> > > >
> > > > > For any procedure I can use procedure-arity. But how to get the number of init arguments for a class?
> > > > >
> > > > > Or maybe there are any other way to make a contract, like in Guide 7.3.9, where one can compare number of arguments and arity of the function, but when using (make-object someclass ...)
> > > > > instead of the function.
> > > > >
> > > > >
> > > > > --
> > > > > Roman Klochkov
> > > > > ____________________
> > > > > Racket Users list:
> > > > > http://lists.racket-lang.org/users
> > > >
> > > >
> > > >
> > > > --
> > > > Roman Klochkov
> > >
> > >
> > >
> > > --
> > > Roman Klochkov
> >
> >
> >
> > --
> > Roman Klochkov
>
>
>
> --
> Roman Klochkov