UndefinedObject.st
author Claus Gittinger <cg@exept.de>
Tue, 03 Jun 1997 12:02:52 +0200
changeset 2672 dc3662188b2c
parent 2416 588d5d510c10
child 3044 a0bbac91639b
permissions -rw-r--r--
added #hasImmediateInstances for VW compatibility

"
 COPYRIGHT (c) 1988 by Claus Gittinger
	      All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"

Object subclass:#UndefinedObject
	instanceVariableNames:''
	classVariableNames:'CreateMinimumProtocolInNewSubclassQuery'
	poolDictionaries:''
	category:'Kernel-Objects'
!

!UndefinedObject class methodsFor:'documentation'!

copyright
"
 COPYRIGHT (c) 1988 by Claus Gittinger
	      All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"
!

documentation
"
    there is only one instance of this class: nil, 
    representing an undefined or otherwise unspecified object.

    All instance variables, array elements and even method/block local 
    variables are initially set to nil.

    Since in Smalltalk/X (and in other smalltalks), nil is represented by 
    a special pointer value (NULL), there can be only one instance of UndefinedObject, 
    and no subclassing is possible. 
    (to be exact: subclassing UndefinedObject is technically possible, 
     but instances of it would not be recognized as being nil 
     - therefore, subclassing is blocked and an error is raised when it is tried)

    For advanced users:
      Beside the above role, nil can be subclassed (!!).
      This creates a class which inherits no protocol whatsoever - not even
      the basic interfaces as defined by the Object class. Subclasses of nil
      are useful if all messages send to instances should trap into the
      #doesNotUnderstand: method. For example, proxy objects are typically defined
      this way.

    [author:]
        Claus Gittinger
"
! !

!UndefinedObject class methodsFor:'initialization'!

initialize
    CreateMinimumProtocolInNewSubclassQuery isNil ifTrue:[
        CreateMinimumProtocolInNewSubclassQuery := QuerySignal new.
        CreateMinimumProtocolInNewSubclassQuery nameClass:self message:#createMinimumProtocolInNewSubclassQuery.
        CreateMinimumProtocolInNewSubclassQuery defaultAnswer:false.
    ].

    "
     UndefinedObject initialize
    "

    "Created: 3.1.1997 / 15:02:40 / cg"
    "Modified: 3.1.1997 / 15:18:33 / cg"
! !

!UndefinedObject class methodsFor:'instance creation'!

basicNew
    "catch new - there MUST be only one nil in the system"

    ^ nil
!

basicNew:size
    "catch new - there MUST be only one nil in the system"

    ^ nil
! !

!UndefinedObject class methodsFor:'Signal constants'!

createMinimumProtocolInNewSubclassQuery
    "return the signal used to ask if the minimum required protocol
     should be created for nil subclasses.
     By default, this is not done, however, the browser answers true
     here, to avoid big trouble with nil subclasses which do not define
     some methods which the inspector needs."

    ^ CreateMinimumProtocolInNewSubclassQuery

    "Created: 3.1.1997 / 15:05:48 / cg"
    "Modified: 3.1.1997 / 15:06:15 / cg"
! !

!UndefinedObject class methodsFor:'queries'!

canBeSubclassed
    "return true, if its allowed to create subclasses of the receiver.
     Return nil here - since it is NOT possible for UndefinedObject"

    ^ false
!

hasImmediateInstances
    "return true if this class has immediate instances.
     Redefined from Behavior"

    ^ true

    "Created: 3.6.1997 / 12:01:39 / cg"
! !

!UndefinedObject methodsFor:'converting'!

decodeAsLiteralArray
    "given a literalEncoding in the receiver,
     create & return the corresponding object.
     The inverse operation to #literalArrayEncoding."

    ^ self

    "Created: 25.2.1997 / 19:18:40 / cg"
!

literalArrayEncoding
    "encode myself as an array literal, from which a copy of the receiver
     can be reconstructed with #decodeAsLiteralArray."

    ^ self

    "Created: 25.2.1997 / 19:18:47 / cg"
! !

!UndefinedObject methodsFor:'copying'!

copy
    "return a shallow copy of myself
     - since there is only one nil in the system return self"

    ^ self
!

deepCopy
    "return a deep copy of myself
     - since there is only one nil in the system return self"

    ^ self
!

deepCopyUsing:aDictionary
    "return a deep copy of myself
     - since there is only one nil in the system return self"

    ^ self
!

shallowCopy
    "return a shallow copy of myself
     - since there is only one nil in the system return self"

    ^ self
!

simpleDeepCopy
    "return a deep copy of myself
     - since there is only one nil in the system return self"

    ^ self
! !

!UndefinedObject methodsFor:'error catching'!

basicAt:index
    "catch array access - its illegal
     defined here since basicAt: in Object ommits the nil-check"

    ^ self notIndexed
!

basicAt:index put:anObject
    "catch array access - its illegal
     defined here since basicAt:put: in Object ommits the nil-check"

    ^ self notIndexed
! !

!UndefinedObject methodsFor:'printing & storing'!

printOn:aStream
    "append a printed representation of the receiver to the
     argument, aStream"

    aStream nextPutAll:'nil'
!

printString
    "return a string for printing myself"

    ^ 'nil'
!

storeOn:aStream
    "append a printed representation of the receiver to the
     argument, aStream, which allows reconstruction of it"

    ^ self printOn:aStream
!

storeString
    "return a string for storing myself"

    ^ 'nil'
! !

!UndefinedObject methodsFor:'subclass creation'!

nilSubclass:action
    "common helper for subclass creation.
     Creates a nil-superclass class. 
     If the CreateMinimumProtocolInNewSubclassQuery answers true,
     entries for the minimum required protocol (#class, #isBehavior 
     and #doesNotUnderstand:) are also automatically created.
     (this query is typically answered by the browser)
     These are required to avoid getting into deep trouble when
     inspecting or debugging instances of this new class.
     The methods get a modified source code to remind you that these
     methods were automatically generated."

    |newClass methodDict method|

    Class withoutUpdatingChangesDo:[
        newClass := action value
    ].
    newClass notNil ifTrue:[
        newClass setSuperclass:nil.
        newClass class setSuperclass:Class.

        newClass methodDictionary size == 0 ifTrue:[
            Class addChangeRecordForClass:newClass.

            CreateMinimumProtocolInNewSubclassQuery raise
            ifTrue:[
                "
                 copy over method objects from Object
                 and modify the source code
                "
                methodDict := MethodDictionary new:3.
                #(#class #isBehavior #doesNotUnderstand:) do:[:sel|
                    method := (Object compiledMethodAt:sel) copy.
                    method source: method source , '
"
*** WARNING
***
*** this method has been automatically created,
*** since all nil-subclasses should respond to some minimum required
*** protocol.
***
*** Inspection and/or debugging of instances may not be possible,
*** if you remove/change this method. 
"
'.
                    methodDict at:sel put:method.
"/                    newClass addChangeRecordForMethod:method
                ].
                newClass methodDictionary:methodDict.
            ]
        ]
    ].
    ^ newClass

    "Modified: 12.6.1996 / 10:46:15 / stefan"
    "Modified: 3.1.1997 / 15:53:21 / cg"
    "Created: 3.1.1997 / 16:00:34 / cg"
!

subclass:nameSymbol instanceVariableNames:instVarNameString classVariableNames:classVarString poolDictionaries:pool category:cat
    "create a new class which has nil as superclass 
     - i.e. traps into #doesNotUnderstand: for all of its messages."

    ^ self 
        nilSubclass:[
                Object class
                    name:nameSymbol  
                    inEnvironment:(Class nameSpaceQuerySignal raise)
                    subclassOf:self
                    instanceVariableNames:instVarNameString
                    variable:false
                    words:true
                    pointers:true
                    classVariableNames:classVarString
                    poolDictionaries:pool
                    category:cat
                    comment:nil
                    changed:true
        ]

    "Modified: 3.1.1997 / 16:00:39 / cg"
!

variableByteSubclass:nameSymbol instanceVariableNames:instVarNameString classVariableNames:classVarString poolDictionaries:pool category:cat
    "create a new class which has nil as superclass 
     - i.e. traps into #doesNotUnderstand: for all of its messages."

    ^ self 
        nilSubclass:[
                Object class
                    name:nameSymbol  
                    inEnvironment:(Class nameSpaceQuerySignal raise)
                    subclassOf:self
                    instanceVariableNames:instVarNameString
                    variable:true
                    words:false
                    pointers:false
                    classVariableNames:classVarString
                    poolDictionaries:pool
                    category:cat
                    comment:nil
                    changed:true
        ]

    "Modified: 3.1.1997 / 16:00:42 / cg"
!

variableSubclass:nameSymbol instanceVariableNames:instVarNameString classVariableNames:classVarString poolDictionaries:pool category:cat
    "create a new class which has nil as superclass 
     - i.e. traps into #doesNotUnderstand: for all of its messages."

    ^ self 
        nilSubclass:[
                Object class
                    name:nameSymbol  
                    inEnvironment:(Class nameSpaceQuerySignal raise)
                    subclassOf:self
                    instanceVariableNames:instVarNameString
                    variable:true
                    words:false
                    pointers:true
                    classVariableNames:classVarString
                    poolDictionaries:pool
                    category:cat
                    comment:nil
                    changed:true
        ]

    "Modified: 3.1.1997 / 16:00:45 / cg"
! !

!UndefinedObject methodsFor:'testing'!

? defaultValue
     "if the receiver is nil, return the defaultValue;
      otherwise, return the receiver.
      This method is redefined from Object;
      the argument is retuned unconditionally here.

      Thus, if foo and bar are simple variables or constants,
          foo ? bar
      is the same as:
          (foo isNil ifTrue:[bar] ifFalse:[foo])

      if they are message sends, the equivalent code is:
          [
              |t1 t2|

              t1 := foo.
              t2 := bar.
              t1 isNil ifTrue:[t2] ifFalse:[t1]
          ] value

      Can be used to provide defaultValues to variables,
      as in:
          foo := arg ? #defaultValue
     "

    ^ defaultValue

    "
     1 ? #default
     nil ? #default 
    "

    "Created: 4.11.1996 / 20:37:09 / cg"
    "Modified: 10.11.1996 / 18:37:13 / cg"
!

basicSize
    "return the number of indexed instvars
     defined here since size in Object ommits the nil-check"

    ^ 0
!

hash
    "return an integer useful as a hash key"

    ^ 0
!

identityHash
    "return an integer useful as a hash key"

    ^ 0
!

isLiteral
    "return true, if the receiver can be used as a literal
     (i.e. can be used in constant arrays)"

    ^ true
!

isNil
    "return true if I am nil - since I am, return true"

    ^ true
!

notNil
    "return true if I am not nil - since I am nil, return false"

    ^ false
!

size
    "return the number of indexed instvars
     defined here since size in Object ommits the nil-check"
 
    ^ 0
! !

!UndefinedObject class methodsFor:'documentation'!

version
    ^ '$Header: /cvs/stx/stx/libbasic/UndefinedObject.st,v 1.31 1997-06-03 10:02:52 cg Exp $'
! !
UndefinedObject initialize!