Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Under the ADT model, what about primitives for all objects? #153

Open
kjx opened this issue Feb 4, 2018 · 1 comment
Open

Under the ADT model, what about primitives for all objects? #153

kjx opened this issue Feb 4, 2018 · 1 comment

Comments

@kjx
Copy link
Contributor

kjx commented Feb 4, 2018

The Full William Cook ADT Model #152 apparently works OK for primitive objects --- but what about the primitive behaviour for all objects? In the Smalltalk/Self/NS object model, each object conceptually has a primitive data part that can be though of has holding its identity (at least), perhaps class too, etc, and then primitive behaviours can be invoked by whatever mechanism to access that primitive data part. Because every object has that primitive data, those primitives (at least) apply to all objects.

I guess the super-hardcore approach would be to say: OK - another cookie for (manipulable) identity.

import "vmObjectADT" as vmObjectADT
class graceObject -> Object  { 
   def cookie is public = vmObjectADT.newUniqueIdentity
   method ==(other : Object) -> Boolean { boolean( vmObjectADT.eq(self.cookie, other.cookie) ) }
   method hash -> Number { integer( vmObjectADT.hash(self) ) }
}

OK, I'm actually tempted to step back to an NS-style solution because I don't think there's anything too terrible about objects having identity built in:

import "vmObjectADT" as vmObjectADT
class graceObject -> Object  { 
   method ==(other : Object) -> Boolean { makeBoolean( vmObjectADT.eq(self, other) ) }
   method hash -> Number { integer( vmObjectADT.hash(self) ) }
}

(Note that because subclasses can override == you've only got a left-handed equals.)
But do we want every object to have an identity-based equals whether we want them to or not?
Time, then, to go to one more remove:

trait equality {
   method ==(other) { isMe(other) }
   method !=(other) {! ==(other) }
   method hash { identityHash }

   method isMe(other) is required { } 
   method identityHash is required { } 
}

trait identity {
   use equality
   method isMe(other) is confidential { makeBoolean( vmObjectADT.eq(self, other) ) }
   method identityHash is confidential -> Number { integer( vmObjectADT.hash(self) ) }
}

If you want to support equality operations, then use equality. You'll have to define isMe and hash, of course, but that's OK. If you're equality really is object identity, then use identity and that's what you get - predefined correct versions of everything. Keeping the names isMe and identityHash makes things clearer, and means if you want to have a more complex equality, you can override == and != without having to alias anything...

While we're at it, what's makeBoolean? Well we want boolean to be the abstract superclass of true and false and other truey and falsey things: but somehow the VM has to return a truth value that will get lifted to the appropriate Grace Boolean. Something like this:

trait boolean { 
 method ifTrue(block) { ifTrue( block ) ifFalse( done ) } 
 //lots of boolean auxiliary methods
} 
object true = {
 inherit boolean
 method prefix! { false }
 method ifTrue(block)ifFalse(_) { block.apply } 
 ...
}
object false = {
 inherit boolean
 method prefix! { true }
 method ifTrue(_)ifFalse(block) { block.apply } 
 ...
}

method mkBoolean( b : VmBoolean ) -> Boolean {
    vmObjectADT.if(b) then(true) else(false)
}
@apblack
Copy link
Contributor

apblack commented Mar 1, 2018

I'm not sure what this "issue" has to do with the language definition. In particular, I don't think that the language definition should prescribe the implementation of numbers, booleans and strings. Different implementations will do it differently. The same goes for exceptions.

Pragmatically, the language spec should say that numbers and booleans exist, and describe their methods. It should also say that you can't "reuse" true or 10.

It would be useful if the language specified a standard way of adding methods to the intrinsic classes like number, boolean and string. One way that we could do this would be to say that if a dialect defines a trait
called numberTrait, then any methods therein would be available on numbers. The effect would as if the the built-in number implementation does a use on that trait, but this effect could be obtained in any way that the implementor chose. [Perhaps it is cleaner to require that NumberTrait be defined, and put the non-basic number operations in that trait, written in Grace. (% for example, which takes care to observe the correct equivalences, could be defined in Grace).

We can do the same with booleanTrait. This would not contain the implementation of the most basic boolean operations, such as ifTrue(_)ifFalse(_) and and(_), but might contain the rarely used ones like nand. AN implementation would still be in control of th representation of booleans, and would be free to inline conditionals, while-loops, etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants