The type/object distinction and possible synthesis of OOP andimperative programming languages


M

Mark Janssen

Hello,

I'm new to the list and hoping this might be the right place to
introduce something that has provoked a bit of an argument in my
programming community.

I'm from the Python programming community. Python is an "interpreted"
language. Since 2001, Python's has migrated towards a "pure" Object
model (ref: http://www.python.org/download/releases/2.2/descrintro/).
Prior to then, it had both types and classes and these types were
anchored to the underlying C code and the machine/hardware
architecture itself. After the 2001 "type/class unification" , it
went towards Alan Kay's ideal of "everything is an object". From
then, every user-defined class inherited from the abstract Object,
rooted in nothing but a pure abstract ideal. The parser, lexer, and
such spin these abstrations into something that can be run on the
actual hardware.

As a contrast, this is very distinct from C++, where everything is
concretely rooted in the language's type model which in *itself* is
rooted (from it's long history) in the CPU architecture. The STL,
for example, has many Container types, but each of them requires using
a single concrete type for homogenous containers or uses machine
pointers to hold arbitrary items in heterogeneous containers (caveat:
I haven't programmed in C++ for a long time, so it's possible this
might not be correct anymore).

My question is: Is there something in the Computer Science literature
that has noticed this distinction/development in programming language
design and history?

It's very significant to me, because as languages went higher and
higher to this pure OOP model, the programmer+data ecosystem tended
towards very personal object hierarchies because now the hardware no
longer formed a common basis of interaction (note also, OOPs promise
of re-usable code never materialized).

It's not unlike LISP, where the power of its general language
architecture tended towards hyperpersonal mini macro languages --
making it hardly used, in practice, though it was and is so powerful,
in theory.

That all being said, the thrust of this whole effort is to possibly
advance Computer Science and language design, because in-between the
purely concrete "object" architecture of the imperative programming
languages and the purely abstract object architecture of
object-oriented programming languages is a possible middle ground that
could unite them all.

Thank you for your time.

Mark Janssen
Tacoma, Washington
 
Ad

Advertisements

S

Steven D'Aprano

Hello,

I'm new to the list and hoping this might be the right place to
introduce something that has provoked a bit of an argument in my
programming community.

I'm from the Python programming community. Python is an "interpreted"
language. Since 2001, Python's has migrated towards a "pure" Object
model (ref: http://www.python.org/download/releases/2.2/descrintro/).
Prior to then, it had both types and classes and these types were
anchored to the underlying C code and the machine/hardware architecture
itself.


Incorrect.

Python's data model has always been 100% object oriented. Prior to the
"class/type" unification, it simply had *two distinct* implementations of
objects: types, which were written in C, and classes, which were written
in Python.

After unification, the two kinds of object were no longer entirely
distinct -- you could then subclass types in Python code, using the same
"class" keyword as you would use for a pure-Python class.

And starting with Python 3, the last vestiges of the distinction have
disappeared. Now, "class" and "type" are mere synonyms. Both built-in
types and custom classes use the same mechanism.

After the 2001 "type/class unification" , it went towards Alan
Kay's ideal of "everything is an object". From then, every user-defined
class inherited from the abstract Object, rooted in nothing but a pure
abstract ideal.

Incorrect. In Python 2.7:


py> class AClass:
.... pass
....
py> issubclass(AClass, object)
False
 
A

Antoon Pardon

Op 15-04-13 12:11, Steven D'Aprano schreef:
Python's data model has always been 100% object oriented. Prior to the
"class/type" unification, it simply had *two distinct* implementations of
objects: types, which were written in C, and classes, which were written
in Python.

After unification, the two kinds of object were no longer entirely
distinct -- you could then subclass types in Python code, using the same
"class" keyword as you would use for a pure-Python class.

And starting with Python 3, the last vestiges of the distinction have
disappeared. Now, "class" and "type" are mere synonyms. Both built-in
types and custom classes use the same mechanism.

I had gotten my hopes up after reading this but then I tried:


$ python3
Python 3.2.3 (default, Feb 20 2013, 17:02:41)
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information..... pass
....
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: type 'slice' is not an acceptable base type


It seems types and classes are still not mere synonyms.
 
D

Dave Angel

Op 15-04-13 12:11, Steven D'Aprano schreef:
Python's data model has always been 100% object oriented. Prior to the
"class/type" unification, it simply had *two distinct* implementations of
objects: types, which were written in C, and classes, which were written
in Python.

After unification, the two kinds of object were no longer entirely
distinct -- you could then subclass types in Python code, using the same
"class" keyword as you would use for a pure-Python class.

And starting with Python 3, the last vestiges of the distinction have
disappeared. Now, "class" and "type" are mere synonyms. Both built-in
types and custom classes use the same mechanism.

I had gotten my hopes up after reading this but then I tried:


$ python3
Python 3.2.3 (default, Feb 20 2013, 17:02:41)
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.... pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: type 'slice' is not an acceptable base type


It seems types and classes are still not mere synonyms.

No, it seems you're trying to use an internal detail as though it were a
supported feature.

From page:
http://docs.python.org/3.3/reference/datamodel.html#types

"""Internal types
A few types used internally by the interpreter are exposed to the user.
Their definitions may change with future versions of the interpreter,
but they are mentioned here for completeness.
"""
 
R

Rotwang

[...]

I had gotten my hopes up after reading this but then I tried:


$ python3
Python 3.2.3 (default, Feb 20 2013, 17:02:41)
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
class vslice (slice):
... pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: type 'slice' is not an acceptable base type


It seems types and classes are still not mere synonyms.

No, it seems you're trying to use an internal detail as though it were a
supported feature.

From page:
http://docs.python.org/3.3/reference/datamodel.html#types

"""Internal types
A few types used internally by the interpreter are exposed to the user.
Their definitions may change with future versions of the interpreter,
but they are mentioned here for completeness.
"""

To be fair, one can't do this either:

Python 3.3.0 (v3.3.0:bd8afb90ebf2, Sep 29 2012, 10:57:17) [MSC v.1600 64
bit (AMD64)] on win32
Type "copyright", "credits" or "license()" for more information.pass

Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
class C(type(lambda: None)):
TypeError: type 'function' is not an acceptable base type


and I don't think that FunctionType would be considered an "internal
detail", would it? Not that I'd cite the fact that not all types can be
inherited from as evidence that types and classes are not synonyms, mind.
 
C

Chris Angelico

Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
class C(type(lambda: None)):
TypeError: type 'function' is not an acceptable base type


and I don't think that FunctionType would be considered an "internal
detail", would it? Not that I'd cite the fact that not all types can be
inherited from as evidence that types and classes are not synonyms, mind.

Actually, I'm not sure how you'd go about inheriting from a function.
Why not just create a bare class, then assign its __call__ to be the
function you're inheriting from?

ChrisA
 
Ad

Advertisements

R

Rotwang

Actually, I'm not sure how you'd go about inheriting from a function.
Why not just create a bare class, then assign its __call__ to be the
function you're inheriting from?

No idea. I wasn't suggesting that trying to inherit from FunctionType
was a sensible thing to do; I was merely pointing out that slice's
status as an internal feature was not IMO relevant to the point that
Antoon was making.
 
T

Terry Jan Reedy

$ python3
Python 3.2.3 (default, Feb 20 2013, 17:02:41)
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.... pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: type 'slice' is not an acceptable base type


It seems types and classes are still not mere synonyms.

Some builtin classes cannot be subclassed. There is an issue to document
which better. That does not mean that it is not a class.
 
S

Steven D'Aprano

Op 15-04-13 12:11, Steven D'Aprano schreef:

Python's data model has always been 100% object oriented. Prior to the
"class/type" unification, it simply had *two distinct* implementations
of objects: types, which were written in C, and classes, which were
written in Python.

After unification, the two kinds of object were no longer entirely
distinct -- you could then subclass types in Python code, using the
same "class" keyword as you would use for a pure-Python class.

And starting with Python 3, the last vestiges of the distinction have
disappeared. Now, "class" and "type" are mere synonyms. Both built-in
types and custom classes use the same mechanism.

I had gotten my hopes up after reading this but then I tried:


$ python3
Python 3.2.3 (default, Feb 20 2013, 17:02:41) [GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.... pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: type 'slice' is not an acceptable base type


It seems types and classes are still not mere synonyms.


You are misinterpreting what you are reading. The mere fact that
something cannot be subclassed doesn't mean anything. That's just a
restriction put on the class by the implementation. It's not even clear
that it is a guaranteed language restriction or a mere accident of
implementation. With a bit of metaclass trickery, I could equally create
a pure-Python class that cannot be easily subclassed.

The proof that types and classes are the same in Python 3 is simple:

py> class C:
.... pass
....
py> type(C) is type(int) is type(type) is type
True

The type of the pure-Python class is type itself.

However, even this can be bypassed, using a metaclass!

py> class D(metaclass=Meta):
.... pass
....
py> type(D) is type
False
py> issubclass(type(D), type)
True


So when using a metaclass, the type of the class is not necessarily type
itself, but it will be a subclass of type.

This does not hold in Python 2.x, not for old-style "classic" classes.
Classic classes are in a world of their own, distinct from types:

# Python 2
py> class C:
.... pass
....
py> type(C)
<type 'classobj'>
py> issubclass(type(C), type)
False



In Python 3, we can expect these two conditions to always hold:

* all instances are instances of object;

* all classes are instances of type.


Notice that this implies that type and object are circularly defined:
object, being a class, is an instance of type, but type, being an object,
is an instance of object:

py> isinstance(type, object)
True
py> isinstance(object, type)
True



These two conditions even apply to unsubclassable objects like slice:

py> isinstance(slice(1, 5, 2), object)
True
py> isinstance(slice, type)
True
 
S

Steven D'Aprano

$ python3
Python 3.2.3 (default, Feb 20 2013, 17:02:41) [GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
class vslice (slice):
... pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: type 'slice' is not an acceptable base type


It seems types and classes are still not mere synonyms.

Some builtin classes cannot be subclassed. There is an issue to document
which better. That does not mean that it is not a class.


I think it is also important to document whether that is a language
feature, or a mere restriction of the implementation. There is an
important distinction to be made between:

"In CPython, you cannot subclass slice or FunctionType. Other Pythons may
have more, or fewer, restrictions."

and:

"No language that calls itself Python is permitted to allow slice and
FunctionType to be subclassable."


If I had a say in this, I would vote for the first case, with the
possible exception of documented singleton types like NoneType and bool.
 
T

Terry Jan Reedy

I think it is also important to document whether that is a language
feature, or a mere restriction of the implementation. There is an
important distinction to be made between:

"In CPython, you cannot subclass slice or FunctionType. Other Pythons may
have more, or fewer, restrictions."

and:

"No language that calls itself Python is permitted to allow slice and
FunctionType to be subclassable."


If I had a say in this, I would vote for the first case, with the
possible exception of documented singleton types like NoneType and bool.

I will keep the above in mind if I write or review a patch. here are 4
non-subclassable builtin classes. Two are already documented. Bool in
one, forget which other. I believe it was recently decided to leave the
other two as is given the absence of any practical use case.
 
Ad

Advertisements

I

Ian Kelly

I will keep the above in mind if I write or review a patch. here are 4
non-subclassable builtin classes. Two are already documented. Bool in one,
forget which other. I believe it was recently decided to leave the other two
as is given the absence of any practical use case.

The four are bool, NoneType, slice and ellipsis, I believe.
 
R

rusi

If I had a say in this, I would vote for the first case, with the
possible exception of documented singleton types like NoneType and bool.

How is bool a singleton type?
 
S

Steven D'Aprano

How is bool a singleton type?


A doubleton, then.


The point being, GvR declared that bool should guarantee the invariant
that True and False are the only instances of bool, and if you can
subclass it, either that invariant is violated, or you can't instantiate
the subclass.
 
8

88888 Dihedral

zipheræ–¼ 2013å¹´4月15日星期一UTC+8上åˆ11時48分05秒寫é“:
Hello,



I'm new to the list and hoping this might be the right place to

introduce something that has provoked a bit of an argument in my

programming community.

I'll state about my opinions about the imperative and
non-imperative part.

If the finite stack depth is used instead of the infinite one,
then the auto local variables of the imperative part
can be implemented quite safe and cheap or at least
self-recoverable from a stack overflow event.

This can save a lot burdens in the GC part in an imperative
language.
 
8

88888 Dihedral

zipheræ–¼ 2013å¹´4月15日星期一UTC+8上åˆ11時48分05秒寫é“:
Hello,



I'm new to the list and hoping this might be the right place to

introduce something that has provoked a bit of an argument in my

programming community.

I'll state about my opinions about the imperative and
non-imperative part.

If the finite stack depth is used instead of the infinite one,
then the auto local variables of the imperative part
can be implemented quite safe and cheap or at least
self-recoverable from a stack overflow event.

This can save a lot burdens in the GC part in an imperative
language.
 
Ad

Advertisements

S

Serhiy Storchaka

The four are bool, NoneType, slice and ellipsis, I believe.
.... if type(getattr(builtins, n)) is type:
.... try:
.... t = type(n, (getattr(builtins, n),), {})
.... except TypeError as e:
.... print(e)
....
type 'bool' is not an acceptable base type
type 'memoryview' is not an acceptable base type
type 'range' is not an acceptable base type
type 'slice' is not an acceptable base type
 
A

Antoon Pardon

Op 16-04-13 05:17, Terry Jan Reedy schreef:
I will keep the above in mind if I write or review a patch. here are 4
non-subclassable builtin classes. Two are already documented. Bool in
one, forget which other. I believe it was recently decided to leave
the other two as is given the absence of any practical use case.

Why should there be a practical use case here? Since classes are in
general subclassable, shouldn't you have a reason to not make them so
instead of people needing to give you a practical use case before you
treat them as you do most of them?

I once had an idea of a slice-like class that I would have liked to
experiment with. As things were I didn't get far because slice not being
subclassable was a major hurdle in getting it practical. Would the end
result have been a practical use case? I don't know, I didn't get the
chance to find out because making a class that looked like a slice
didn't work either. Python wanted, maybe still wants, a real slice in a
number of circumstances and not a ducktyped slice-like object.

Now maybe there are good reasons for slice not being subclassable but
there not being a practical use case doesn't seem to be one in this case.
 
T

Terry Jan Reedy

Op 16-04-13 05:17, Terry Jan Reedy schreef:

Why should there be a practical use case here?

As a practical matter, the change is non-trivial. Someone has to be
motivated to write the patch to enable subclassing, write tests, and
consider the effect on internal C uses of slice and stdlib Python used
of slice (type() versus isinstance).
Since classes are in general subclassable,

if written in Python, but not if written in C.
I once had an idea of a slice-like class that I would have liked to
experiment with.

Did the idea actually require that instances *be* a slice rather than
*wrap* a slice?
 
Ad

Advertisements

E

Ethan Furman

--> import builtins
--> for n in dir(builtins):
... if type(getattr(builtins, n)) is type:
... try:
... t = type(n, (getattr(builtins, n),), {})
... except TypeError as e:
... print(e)
...
type 'bool' is not an acceptable base type
type 'memoryview' is not an acceptable base type
type 'range' is not an acceptable base type
type 'slice' is not an acceptable base type

Well that bumps our count to five then:

--> NoneType = type(None)
--> NoneType
<class 'NoneType'>
--> class MoreNone(NoneType):
.... pass
....
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: type 'NoneType' is not an acceptable base type
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top