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

From: Matthias Felleisen (matthias at ccs.neu.edu)
Date: Fri Jun 6 12:12:07 EDT 2014

The new expression dos not designate an initial field value for x even though the contract says there must be one. You can also specify 'a as the initial value for x inside the class and the contract system won't tell you that your object does not have a correct field value. When you eventually dereference the object you get a contract error. But if you also have (field (y (* x x)) further down, the error message shows again that the init contract isn't checked. 


On Jun 6, 2014, at 12:06 PM, Robby Findler <robby at eecs.northwestern.edu> wrote:

> 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.