From the little I know, it seems to me that Tcl 8.6 could support a
very similar model of concurrency.
Well, the other day I posted a similar comment on the wiki page for
coroutine and DKF answered
"...but it looks like what they're really doing is lightweight
threads, not coroutines. We might want to suggest “borrowing” their
channel abstraction though; it's a model that works really well."
jima
They're not the same thing. Though there are some similarities,
goroutines are parallel-schedulable and so are more like threads than
coroutines (they are actually done as green threads over a native
thread pool). There is a yield-like operation, but that's actually
sending messages over a channel. They've still got a shared state
model, though with some fairly grisly constraints on observability of
state changes.
Donal.
Though it appears from their docs that they discourage using shared
state to communicate between goroutines.
But yes, it's clear that Tcl coroutines and goroutines are different.
My question was really, could we do essentially the same thing as
goroutines and Go chans on top of Tcl coros. And would that be worth
doing?
Tcl already has the technology called "libmsgque"
you can create a tcl CO process using fork, thread or spawn
->
http://libmsgque.sourceforge.net/tclmsgque/group__tclmsgque.htm#tcl_slave
and this work for all supported programming-languages
mfg
Andreas Otto (aotto1968)
When Miguel was planning the NRE work, I remember we dreamt about all
those sexy applications of the "tree of frames" (as opposed to the old
linear, monolithic stack of frames), and mentioned green threads.
Basically, interspersing Tcl execution with [yield] points, with the
help of a dedicated scheduler for fairness, is entirely possible. On
tough point though is to avoid getting stuck in a blocking syscall.
That's what the OS's scheduler is good at, and redoing in userland is
always less efficient :/
-Alex
> They're not the same thing. Though there are some similarities,
> goroutines are parallel-schedulable and so are more like threads than
> coroutines (they are actually done as green threads over a native
> thread pool). There is a yield-like operation, but that's actually
> sending messages over a channel. They've still got a shared state
> model, though with some fairly grisly constraints on observability of
> state changes.
So... how similar are they to something like Erlang's "actor" model?
They're fairly close to the actor model of Erlang and Scala though the
typed pi-calculus is even more representative (since you can send
channels over channels). It's not clear to me how Go handles
interactions with state outside a goroutine; there's some theoretical
impurity there, and the documentation provided so far doesn't make it
clear what the deep limitations are (and in fact deliberately
obfuscates things in order to encourage the use of channel
communications and probably to allow for flexibility of implementation
too).
Donal.
In the "golang-nuts" Google group there was a question about the
equivalent of thread-local storage for goroutines, and the answer was
that Go doesn't provide any such thing. So far as I can tell from
browsing around, global state is universally available in goroutines,
and you can get yourself tied in all of the usual concurrency knots if
you share data between goroutines in that way. In addition, the
runtime library has support for mutexes.
It sounds like the usual thing to do is to let goroutines allocate
their own state, and communicate through channels, rather than access
global state, in accordance with the "Doctor, it hurts when I do
this..." principle: "Well, Don't Do That, Then."
They can fake goroutine-local state easily enough if they can get the
identity of the current goroutine. That's how Tcl does thread-locals
under the covers.
> In addition, the runtime library has support for mutexes.
If there are mutexes, they'll be sharing state. Nobody would use a
mutex if they weren't sharing state. (Mind you, you can also implement
a mutex using a goroutine...)
> It sounds like the usual thing to do is to let goroutines allocate
> their own state, and communicate through channels, rather than access
> global state, in accordance with the "Doctor, it hurts when I do
> this..." principle: "Well, Don't Do That, Then."
That was my impression too.
Donal.
Looks like a cool language, from the hype, but one thing stuck out
which seems very promising:
* Go's type system has no hierarchy, so no time is spent defining the
relationships between types. Also, although Go has static types the
language attempts to make types feel lighter weight than in typical OO
languages.
Wow! Finally someone has dared to state the obvious: type hierarchy is
expensive and difficult to understand, even for a compiler.
That's essentially duck typing. In a compiled language, that's unusual
(and is in fact something that's brought in from scripting languages
if I've understood the FAQ right). This is something to watch to see
how well it works in practice.
> Wow! Finally someone has dared to state the obvious: type hierarchy is
> expensive and difficult to understand, even for a compiler.
Compilers can cope well enough. It's programmers that have the problem
it seems; most people tend to find deep is-a-kind-of hierarchies
difficult to comprehend. (C++'s insane slowness to compile is due to
other issues, such as turing-complete template complexity.)
Donal.
In some cases it goes beyond the hierarchy's depth, and there's a
shared responsibility: think about Eiffel's esoteric compilation
messages, especially in the presence of generics, or covariance/
contravariance clashes with the "like" operator. Even a perfectly
rigorous programmer can be helpless in front of the system's own
contradictions ;-)
-Alex
I don't know Eiffel *that* well. However, I do know that there's a
tendency for generics/templates to lead to mystifying error messages
and in many languages (Java is not good, C++ is famously bad, and
Standard ML can be pretty nasty too). But ultimately, the problem
comes when you try to establish type relationships between derived
types (functions, arrays, modifiable variables) and not principal
types (simple values, structures). The complexity of objects is an
interesting topic.
So this discussion isn't mistaken for comp.lang.misc :-) Tcl's objects
don't work this way at all. The fact that you can restructure the type
hierarchy underneath the feet of everything means that what we've got
is not really a type hierarchy at all, but something else. (A
responsibility hierarchy perhaps?)
Donal.
Indeed. And talking about hierarchies, Tcl_ObjTypes display absolutely
zero null nada ability for polymorphism, which is a longstanding itch
of mine. The whole core is sprinkled with "if (objPtr->typePtr ==
&tclFooType)", so that if you want to extend Foo you cannot do it
without a core patch. Moreover, the patch tends to be scattered over
several places if Foo happens to have fast conversion shortcuts with
other types, like List/Dict.
One way out would be something like "if (INHERITS_FROM(objPtr-
>typePtr,tclFooType))"
with
#define INHERITS_FROM(t1,t2) \
(t1)&&((t1)->inheritsFrom ? \
(t1)->inheritsFrom(t2) : \
((t1)==(t2)))
and the obvious extension of the Tcl_ObjType struct with an
inheritFrom "method", left to NULL for primitive types to minimize
overhead.
The only problem of course is to do that in an ABI-stable manner.
Maybe letting sizeof(Tcl_ObjType) be returned by a stub-reachable
function ?
If that's for Tcl9 of course, no problem, but let's not be beaten
again later, and put sizeof(X) in struct X for all public
structures ;-)
-Alex
You're only getting antsy about this because you're thinking of a
Tcl_Obj as an object. It's not. It's a value, but Tcl_Value was taken
for something else at the time. There's simply no type hierarchy
involved with the basic value types. It's just that some operations
understand multiple types (well, that's also inaccurate, but not
nearly as bad as what you were saying).
Donal.
I know there's no type hierarchy :)
I was just arguing it would be cool to be able to extend a type
instead of duplicating.
For example, a BitSet type backed by a bit array but exposing the List
API [lindex/lset].
-Alex
Extending? Adding new operations?
> For example, a BitSet type backed by a bit array but exposing the List
> API [lindex/lset].
Not really; that's really just type abuse given that nobody currently
has an expectation of such restricted types in Tcl right now. For
example, "But I can't use [lset] to put a dictionary in that 'list'!
Something's wrong with it!" Just because it would be technically
possible to do such things doesn't mean that I believe it to be a good
idea...
(I might relax a bit sometime in the future when it comes to arrays. I
have some ideas there, though they're not really "types" so much as
"storage/mapping models".)
Donal.
-> http://www.ibm.com/developerworks/java/library/j-jtp11137.html
I like that the steady work on libmsgque ...
-> http://libmsgque.sourceforge.net/
has a very small impact on the state of the art SW industry
mfg
Andreas Otto
I have an essentially organic distaste for type extensions so it is
somewhat difficult for me to explain via rational argument.
My first issue is that you need to support additional language
features to create a type extension, so you get automatic language
bloat and measurable technical complication.
As a consequence of this first issue, there are two modes of
programming: direct programming and programming by diff/patch. To
understand the problem of programming by diff/patch, imagine if you
had to update source code by typing in the diff of the original code
and what you want the new code to look like. This is what programming
via diff/patch is like.
On top of the programming issues, readers of source code must read via
diff/patch. You have to perform mental gymnastics to replace what
appears on paper/monitor with the actual in-memory structure of the
type.
My second issue is that I don't think the real world supports type
hierarchies. They are a logical construct which "does not model" the
real world. Unlike most models, type hierarchies add complications to
the model which do not exist in the real world. Usually models
simplify reality, but this is not the case with type hierarchies.
Note that "type hierarchies" are different from "object hierarchies".
One example of an object hierarchy is type restriction, or filters, or
subsets. Although objects don't exist in a physical hierarchy, it is
easy to pick subsets of any group of objects based upon an arbitrary
filter.
Of course I have a lot of respect for developers who can do all the
mental gymnastics required to work with type hierarchies, I just hope
they don't start directing movies or writing novels.
I should mention that I'm not keen on changing Tcl's type system.
> My first issue is that you need to support additional language
> features to create a type extension, so you get automatic language
> bloat and measurable technical complication.
I understand, and the impact of Alexandre's idea (it's not mine!) would
be substantive and paid by everyone, and yet there's not much certainty
of payoff commensurate with that clear cost.
> As a consequence of this first issue, there are two modes of
> programming: direct programming and programming by diff/patch. To
> understand the problem of programming by diff/patch, imagine if you
> had to update source code by typing in the diff of the original code
> and what you want the new code to look like. This is what programming
> via diff/patch is like.
>
> On top of the programming issues, readers of source code must read via
> diff/patch. You have to perform mental gymnastics to replace what
> appears on paper/monitor with the actual in-memory structure of the
> type.
You lost me there (but did put in my mind how people used to work with
Minix before the rise of Linux...)
> My second issue is that I don't think the real world supports type
> hierarchies. They are a logical construct which "does not model" the
> real world. Unlike most models, type hierarchies add complications to
> the model which do not exist in the real world. Usually models
> simplify reality, but this is not the case with type hierarchies.
I must respectfully disagree. A *good* type hierarchy does indeed model
the world, and I know a number of colleagues of mine who have specific
training in performing that modeling step. However, one of the key
things is that the "is-a-specialized-kind-of" relationship (the
foundation of a type hierarchy as classically understood) is only one of
the relations that can be used to couple the categories and instances of
ones model; there are many others too. Object Oriented Analysis and OO
Design teach the same thing (since they're really all facets of the same
general problem area; how to model the real world).
Alas, many people get it wrong and misuse the subtype relationship
badly. If all your 3-year-old has is a hammer, watch out for the furniture.
> Note that "type hierarchies" are different from "object hierarchies".
> One example of an object hierarchy is type restriction, or filters, or
> subsets. Although objects don't exist in a physical hierarchy, it is
> easy to pick subsets of any group of objects based upon an arbitrary
> filter.
Are you thinking in terms of a whole-part (a.k.a. container-component)
relationship here? That's totally different. If not, you're getting a
bit too metaphysical for me to grasp it. :-)
> Of course I have a lot of respect for developers who can do all the
> mental gymnastics required to work with type hierarchies, I just hope
> they don't start directing movies or writing novels.
I don't hold my breath waiting for (most[*]) directors and authors to
write high-quality programs or type hierarchies either. It's not a
helpful point. ;-)
To return to my real point from earlier though, a lot of (and in fact
unfortunately far too many) programmers massively abuse the subtype
relationship to do all sorts of nasty things. (We'll draw a gentle veil
over what C++ does with templates.) This is often because it is easier
to do so at first due to language support; mainstream language designers
have been largely fixated on subtypes for a few decades now. (Maybe Go
is marking a shift away from this approach? Time will tell...)
Donal.
[* As it happens, I personally know some exceptions; people exist who
are both decent programmers and directors. It just goes to show that
ones job is not actually a fundamental characteristic, but rather
just a role. OTOH, the fact of their humanity *is* (so far as anyone
can really prove) a fundamental characteristic, as is the history of
what jobs they have worked in. ]
Hear! Just within the last few days I was telling our Chief Engineer that
Tcl tends to minimize syntax and reserved words and complex types in favor
of personal responsibility. You can do almost anything, just take
responsibility for what you do.
QOTW?
It's structural subtyping a la Ocaml, AFAICT. There are arguments
pro/con structural vs nominal typing, but generally I much prefer this
approach.
It will be interesting to see if Go catches on, and whether it does so
as a general purpose language, or perhaps in a niche such as Android
programming.
-- Neil
One of the recent articles mentioned the fact that the Android
platform either is currently, or expected to be by the end of year (I
don't remember the exact quote) the largest Linux platform in
existence. I hadn't really thought of that before the article.
You are confusing subtyping and inheritance. Subtyping means simply
creating a new type that permits at least the same set of operations as
the base type. It says nothing about how these are implemented.
Inheritance is then a specific mechanism for reusing code to implement
subtyping, which corresponds to your notion of programming by
diff/patch, but is not the only approach by a long way.
[...]
>
> My second issue is that I don't think the real world supports type
> hierarchies. They are a logical construct which "does not model" the
> real world. Unlike most models, type hierarchies add complications to
> the model which do not exist in the real world. Usually models
> simplify reality, but this is not the case with type hierarchies.
Are you advocating a form of Platonic realism, in which there is some
objective "real world" out there which corresponds directly to some
natural approach to modelling? Personally, I believe that the intended
interpretation and application has quite an impact on what models make
sense (cf. the definition of "model" in logical semantics).
As a case in point, do you believe there is a relationship between the
concepts of "chair" and "furniture"? If you were coming up with a model
of "objects in my house", then you'd almost certainly say "yes, there is
a kind-of (subtype) relationship between them". If you were instead
modelling the morphology of words in the English language, then you may
instead prefer not to model such a relationship, but instead to model
"chairs" and "chair" as related to the lexeme "CHAIR".
[...]
-- Neil
Well, technically, I guess, this article (which I think I was
remembering when I wrote that)
is talking about Google's OS. However, the thrust of the article was
about google and linux, so I guess if Google's OS becomes one of the
largest platforms, that might make it the largest Linux platform.
Anyways, I wanted to point to the article that I had been remembering.
On a related note, some interesting discussion about Go:
http://www.cowlark.com/2009-11-15-go/
http://dalkescientific.com/writings/diary/archive/2009/11/15/100000_tasklets.html
The last reference is interesting if people want some ammunition for
advocating dynamic languages.
-- Neil
No I'm not confusing anything. You might be, can't really tell.
First, you can use words like subtyping, inheritance or extension, it
makes no difference. My point is that "flat" hierarchies obviously
don't need language features to support inheritance. This should be
obvious. So, languages which support type hierarchies obviously have
at least two completely different mechanisms in which to define types:
directly and by reference to some other type. The by reference is much
more complex than the direct method. Adding additional methods in
which to support and define type hierarchies does not make programming
any simpler, this should also be obvious.
But, some people like the complexity, I don't. It isn't only difficult
to do correctly, but the resulting model is often contrived. (Not
always, as others have said: it is just difficult to get right).
>
> > My second issue is that I don't think the real world supports type
> > hierarchies. They are a logical construct which "does not model" the
> > real world. Unlike most models, type hierarchies add complications to
> > the model which do not exist in the real world. Usually models
> > simplify reality, but this is not the case with type hierarchies.
>
> Are you advocating a form of Platonic realism, in which there is some
> objective "real world" out there which corresponds directly to some
> natural approach to modelling? Personally, I believe that the intended
> interpretation and application has quite an impact on what models make
> sense (cf. the definition of "model" in logical semantics).
>
> As a case in point, do you believe there is a relationship between the
> concepts of "chair" and "furniture"? If you were coming up with a model
> of "objects in my house",
Object in my house = a collection
> then you'd almost certainly say "yes, there is
> a kind-of (subtype) relationship between them".
Ah, this is the problem: the relationship is also a "type". Using a
static subtype (pointer) relationship to a collection requires a map.
Simple, but relatively limited since every mapping is identical. If
the relationship is also a type, you can create a triple (Me<->Mine<-
>Stuff) or (Chair<->Kind Of<->Furniture)
When you make a static "kind-of" relationship between chair and
furniture, you cannot reuse that relationship like this:
(Furniture<->Kind Of<->Stuff).
With the type of relationships above, I can say that this is legal:
(Me<->Mine<->Chair), since I can own "Stuff", I can own "Chair". And
if that relationship is valid, I know that (Me<->Mine<->Furniture) is
true, and I can ask what other "Kind Of" furniture are "Mine".
Note there is no type inheritance here. There are no type hierarchies,
but there are object hierarchies. But just because two types can be
connected through a "Kind Of" relationship does not mean they need to
share "any" internal structure.
> If you were instead
> modelling the morphology of words in the English language, then you may
> instead prefer not to model such a relationship, but instead to model
> "chairs" and "chair" as related to the lexeme "CHAIR".
This is completely different. Now you are talking about a combination
of mappings/tagging and an ordered hierarchy of "same typed" objects.
For instance, in a directory structure, subdirectories are not
"subtypes" of the parent. Permissions on the directories are just
local tags (or consider them part of the directory object).
These two statements are contradictory.
> My point is that "flat" hierarchies obviously
> don't need language features to support inheritance. This should be
> obvious. So, languages which support type hierarchies obviously have
> at least two completely different mechanisms in which to define types:
> directly and by reference to some other type. The by reference is much
> more complex than the direct method.
Do you have any evidence to support this assertion?
> Adding additional methods in
> which to support and define type hierarchies does not make programming
> any simpler, this should also be obvious.
>
> But, some people like the complexity, I don't. It isn't only difficult
> to do correctly, but the resulting model is often contrived. (Not
> always, as others have said: it is just difficult to get right).
>
>>> My second issue is that I don't think the real world supports type
>>> hierarchies. They are a logical construct which "does not model" the
>>> real world. Unlike most models, type hierarchies add complications to
>>> the model which do not exist in the real world. Usually models
>>> simplify reality, but this is not the case with type hierarchies.
>> Are you advocating a form of Platonic realism, in which there is some
>> objective "real world" out there which corresponds directly to some
>> natural approach to modelling? Personally, I believe that the intended
>> interpretation and application has quite an impact on what models make
>> sense (cf. the definition of "model" in logical semantics).
>>
>> As a case in point, do you believe there is a relationship between the
>> concepts of "chair" and "furniture"? If you were coming up with a model
>> of "objects in my house",
>
> Object in my house = a collection
>
>> then you'd almost certainly say "yes, there is
>> a kind-of (subtype) relationship between them".
>
> Ah, this is the problem: the relationship is also a "type". Using a
> static subtype (pointer) relationship to a collection requires a map.
Eh? In what way is a relationship a type? And why would this require a map?
> Simple, but relatively limited since every mapping is identical. If
> the relationship is also a type, you can create a triple (Me<->Mine<-
>> Stuff) or (Chair<->Kind Of<->Furniture)
Yes, you can express arbitrary relationships with triples, cf. RDF, but
what does that have to do with anything?
>
> When you make a static "kind-of" relationship between chair and
> furniture, you cannot reuse that relationship like this:
>
> (Furniture<->Kind Of<->Stuff).
Umm... sure you can.
>
> With the type of relationships above, I can say that this is legal:
>
> (Me<->Mine<->Chair), since I can own "Stuff", I can own "Chair".
The only valid reason for making that assertion would be if you also
knew that all chairs are stuff -- i.e., that your logic has some notion
of subsumption/subtyping.
And
> if that relationship is valid, I know that (Me<->Mine<->Furniture) is
> true, and I can ask what other "Kind Of" furniture are "Mine".
[...]
>
>> If you were instead
>> modelling the morphology of words in the English language, then you may
>> instead prefer not to model such a relationship, but instead to model
>> "chairs" and "chair" as related to the lexeme "CHAIR".
>
> This is completely different. Now you are talking about a combination
> of mappings/tagging and an ordered hierarchy of "same typed" objects.
> For instance, in a directory structure, subdirectories are not
> "subtypes" of the parent. Permissions on the directories are just
> local tags (or consider them part of the directory object).
That was my point. You cannot make blanket statements like "type
hierarchies are unnatural" without first stating what your domain of
interest is. Sometimes they're useful, sometimes they're not.
-- Neil
> > My point is that "flat" hierarchies obviously
> > don't need language features to support inheritance. This should be
> > obvious. So, languages which support type hierarchies obviously have
> > at least two completely different mechanisms in which to define types:
> > directly and by reference to some other type. The by reference is much
> > more complex than the direct method.
>
> Do you have any evidence to support this assertion?
Why don't you give an example which proves the assertion wrong. It
would be impossible for me to "prove" by example the assertion, but
you can easily disprove it with one example.
> > Object in my house = a collection
>
> >> then you'd almost certainly say "yes, there is
> >> a kind-of (subtype) relationship between them".
>
> > Ah, this is the problem: the relationship is also a "type". Using a
> > static subtype (pointer) relationship to a collection requires a map.
>
> Eh? In what way is a relationship a type? And why would this require a map?
Well, below you know about RDF, so I assume you know that each part of
the triple is an object of some type.
> > Simple, but relatively limited since every mapping is identical. If
> > the relationship is also a type, you can create a triple (Me<->Mine<-
> >> Stuff) or (Chair<->Kind Of<->Furniture)
>
> Yes, you can express arbitrary relationships with triples, cf. RDF, but
> what does that have to do with anything?
Everything. Independent object/type creation. The relationship (Kind
Of) is also a type.
> > When you make a static "kind-of" relationship between chair and
> > furniture, you cannot reuse that relationship like this:
>
> > (Furniture<->Kind Of<->Stuff).
>
> Umm... sure you can.
>
Only if "Kind Of" is a type.
>
> > With the type of relationships above, I can say that this is legal:
>
> > (Me<->Mine<->Chair), since I can own "Stuff", I can own "Chair".
>
> The only valid reason for making that assertion would be if you also
> knew that all chairs are stuff -- i.e., that your logic has some notion
> of subsumption/subtyping.
That is not true. You dynamically create the relationships. You don't
"know" anything until you ask. Your system might have the following
triples:
(Me<->Mine<->My Chair)
(My Chair<->Kind Of<->Chair)
(Chair<->Kind Of<->Furniture)
(Furniture<->Kind Of<->Stuff)
The "language" does not have a notion of subtyping, just creating
triples.
> That was my point. You cannot make blanket statements like "type
> hierarchies are unnatural" without first stating what your domain of
> interest is. Sometimes they're useful, sometimes they're not.
So I should write a book instead? I'm not saying that all type
hierarchies are unnatural, I just wish someone would present a natural
one as an example. Even if such an example emerges, why do the
subtypes need to be constructed via this formal mechanism? Copy/Paste
& Edit is great way of creating a new subtype.
I know that my terminology is loose. Is there a difference between
data subtypes and class/object subtypes which include behaviors? How
about inheritance vs. extensions vs. implementations? All of these are
different, yet pretty much the same thing: they all require language
support to get from the original thing to the new thing.
But I would like to separate out one type of "subtyping" that seems
easy for me to understand (amazing!), and produces subtypes whose
members are a true subset of the original type. The definition still
requires language support, but the subtype mechanisms are pre-defined.
Not sure if there is an actual name for it, but in XML-Schema they
call it derivation by restriction. Although not required in the XML-
Schema system, one additional requirement I would add is that type
derivation cannot span more than one namespace, in other words, start
with the primitive types in XML-Schema/programming language and derive
new types in the target namespace, no imports. Also, once a simple
type is used in a complex/structural type, it can't be further
restricted.
There is an article which almost gets at my general distaste for
subtyping:
http://www.javaworld.com/javaworld/jw-08-2003/jw-0801-toolbox.html
(Why Extends is Evil)
Interfaces are probably my favorite abstraction. They are built from
the ground up and hide potentially vast technical differences behind a
common model. Two well known interfaces are "unix files": everything
is a file, and a URI. Or more on topic: tcl channels.
> So I should write a book instead? I'm not saying that all type
> hierarchies are unnatural, I just wish someone would present a natural
> one as an example.
Look at the java.util Collection hierarchies plenty
of natural and useful examples
> Even if such an example emerges, why do the
> subtypes need to be constructed via this formal mechanism? Copy/Paste
> & Edit is great way of creating a new subtype.
>
It's a great way of creating a mess, and doesn't provide the same results.
If a type B is a "subtype" of A that is just a copy of the code and new
stuff tacked on, then even though type B can do everything an A can
other areas can't treat B as an A since they are different.
and maintainance would be a disaster - you would end up with multiple
copies of bugs all over the place.
Bruce
Why is it so hard to produce one example? Of course data structures
are more naturally hierarchical than models from the real world. The
point is that if you "define" B is a subtype of A, it is obviously
natural...by definition.
> > Even if such an example emerges, why do the
> > subtypes need to be constructed via this formal mechanism? Copy/Paste
> > & Edit is great way of creating a new subtype.
>
> It's a great way of creating a mess, and doesn't provide the same results.
>
I'm not interested in the same results, I'm interested in easier
programming and better results.
> If a type B is a "subtype" of A that is just a copy of the code and new
> stuff tacked on, then even though type B can do everything an A can
> other areas can't treat B as an A since they are different.
>
> and maintainance would be a disaster - you would end up with multiple
> copies of bugs all over the place.
I already explained that the concept of interface is preferable to
subtyping. Subtyping takes A, changes it a little and creates a new
type, bound to A, but a little different...just enough to cause
trouble. An interface has the potential of taking completely different
(in details) objects and making them look the same. In other words,
you do work to simplify when you create an interface, but you do
almost no work to complicate stuff when you create a subtype.
Subtyping is like free complications which you can pay for later...and
you will pay for them.
It seems obvious to me why many developers prefer subtyping: it is
quick and easy and you don't pay for it until later. In fact, if you
are the one which produces the class which is to be subtyped, you
never have to pay! It is kind of like "details are left as an exercise
for the reader".
How exactly has Tcl survived without types or type hierarchies?
Not that I'm defending anyone here, but the cost of Go in there is
probably due to the startup and teardown of the garbage collection
engine. GC has a real cost, and it's at startup and teardown (well,
depending on how you do it) when you really pay. They also pay for
having to have memory management always be a global operation rather
than per-thread; the goroutine abstraction is nice, but having thread-
affinity for resources is just a huge win (and is a big part of Tcl's
Secret Sauce).
Donal.
There are types. They're just not permanently attached to values;
they're more of a characteristic of operations. It is thus a part of
the [llength] operation that it operates on values of list type.
However, that a value is of list type is merely a transient thing
(since we use "duck typing" really). That we maintain the type of
value at all for any time after an operation is just an optimization;
it's not a vital part of the language's semantics.
Because of this fundamentally different approach to types, the type
hierarchy question simply isn't pressing. That a value is of one type
does not preclude it from being of another type, whatever the
relationship of those types to each other is. (Arguably types in Tcl
are just arbitrary subsets over the domain of all strings.)
Donal.
Sometimes I hate taking people up on their offer. Why _not_ look at
the java.util Collection?
Why not start at the very top and breath in the pathology?
http://java.sun.com/j2se/1.4.2/docs/api/java/util/Collection.html or
newer:
http://java.sun.com/j2se/1.5.0/docs/api/java/util/Collection.html
"A collection represents a group of objects, known as its elements.
Some collections allow duplicate elements and others do not. Some are
ordered and others unordered. The JDK does not provide any direct
implementations of this interface: it provides implementations of more
specific subinterfaces like Set and List. This interface is typically
used to pass collections around and manipulate them where maximum
generality is desired."
So the collection offers no direct implementations, check elsewhere
for working code. Of course the manpage is longer than Tcl's list
manpage which actually describes working code.
But check out the last sentence: "This interface is typically used to
pass collections around and manipulate them where maximum generality
is desired."
So basically this interface is used to avoid type checking. This is a
perfect example of paying up front for basically the right to pay more
later on. The very top of the collection hierarchy is advertised as a
way to avoid all the nasty requirements imposed by this ugly system.
Not sure if you are going to use a list or an array, a bag or a set or
a queue or a sorted map? Just use a collection as the type.
Probably the developers are happy that their lists and bags can
contain any type. Like wow! Dog types and Cat types in the same bag,
oops "collection", we might need to pass this around.
Because it is your assertion -- the burden of proof is on you. You
stated that building types by reference to other types is more complex
than the "direct" method (whatever that is). If this were true, it would
rule out *all* compound types, not just subtypes.
>
>>> Object in my house = a collection
>>>> then you'd almost certainly say "yes, there is
>>>> a kind-of (subtype) relationship between them".
>>> Ah, this is the problem: the relationship is also a "type". Using a
>>> static subtype (pointer) relationship to a collection requires a map.
>> Eh? In what way is a relationship a type? And why would this require a map?
>
> Well, below you know about RDF, so I assume you know that each part of
> the triple is an object of some type.
That's not true, RDF triples are of form (subject,predicate,object) --
the subject and objects are objects, but the predicate is a predicate
(relation).
>
>>> Simple, but relatively limited since every mapping is identical. If
>>> the relationship is also a type, you can create a triple (Me<->Mine<-
>>>> Stuff) or (Chair<->Kind Of<->Furniture)
>> Yes, you can express arbitrary relationships with triples, cf. RDF, but
>> what does that have to do with anything?
>
> Everything. Independent object/type creation. The relationship (Kind
> Of) is also a type.
>
>
>>> When you make a static "kind-of" relationship between chair and
>>> furniture, you cannot reuse that relationship like this:
>>> (Furniture<->Kind Of<->Stuff).
>> Umm... sure you can.
>>
>
> Only if "Kind Of" is a type.
Not even slightly. E.g. consider Java, where we can define exactly this
hierarchy as subtypes without the "Kind Of" relation being reified as a
separate type:
interface Stuff {}
interface Furniture extends Stuff {}
interface Chair extends Furniture {}
>
>>> With the type of relationships above, I can say that this is legal:
>>> (Me<->Mine<->Chair), since I can own "Stuff", I can own "Chair".
>> The only valid reason for making that assertion would be if you also
>> knew that all chairs are stuff -- i.e., that your logic has some notion
>> of subsumption/subtyping.
>
> That is not true. You dynamically create the relationships. You don't
> "know" anything until you ask. Your system might have the following
> triples:
> (Me<->Mine<->My Chair)
> (My Chair<->Kind Of<->Chair)
> (Chair<->Kind Of<->Furniture)
> (Furniture<->Kind Of<->Stuff)
>
> The "language" does not have a notion of subtyping, just creating
> triples.
Sure, but your statement was that you can own chairs because you can own
stuff. This is only valid if you know that chairs are a kind of stuff --
so either you have such a mechanism built in to your logic, or you
manually specify it, as in FOL:
\forall x.Chair(x) => Stuff(x)
Either way, you are describing a subtyping/subsumption relationship.
>
>> That was my point. You cannot make blanket statements like "type
>> hierarchies are unnatural" without first stating what your domain of
>> interest is. Sometimes they're useful, sometimes they're not.
>
> So I should write a book instead? I'm not saying that all type
> hierarchies are unnatural,
I believe that is exactly what you said: "I don't think the real world
supports type hierarchies".
> I just wish someone would present a natural
> one as an example. Even if such an example emerges, why do the
> subtypes need to be constructed via this formal mechanism? Copy/Paste
> & Edit is great way of creating a new subtype.
I thought the Chair->Furniture->Stuff example was sufficient. They don't
need to be created by any formal mechanism, but they do still exist.
Copy/Paste & Edit is a valid (if suboptimal) strategy for *implementing*
a subtype, but this is not the same as specifying such a relationship.
The difference is between "extends" (inheritance) and "implements"
(subtyping) in Java.
>
> I know that my terminology is loose. Is there a difference between
> data subtypes and class/object subtypes which include behaviors? How
> about inheritance vs. extensions vs. implementations? All of these are
> different, yet pretty much the same thing: they all require language
> support to get from the original thing to the new thing.
>
> But I would like to separate out one type of "subtyping" that seems
> easy for me to understand (amazing!), and produces subtypes whose
> members are a true subset of the original type. The definition still
> requires language support, but the subtype mechanisms are pre-defined.
> Not sure if there is an actual name for it, but in XML-Schema they
> call it derivation by restriction. Although not required in the XML-
> Schema system, one additional requirement I would add is that type
> derivation cannot span more than one namespace, in other words, start
> with the primitive types in XML-Schema/programming language and derive
> new types in the target namespace, no imports. Also, once a simple
> type is used in a complex/structural type, it can't be further
> restricted.
>
> There is an article which almost gets at my general distaste for
> subtyping:
>
> http://www.javaworld.com/javaworld/jw-08-2003/jw-0801-toolbox.html
> (Why Extends is Evil)
This article backs up my point: it favours subtyping (implements) over
inheritance (extends).
>
> Interfaces are probably my favorite abstraction. They are built from
> the ground up and hide potentially vast technical differences behind a
> common model. Two well known interfaces are "unix files": everything
> is a file, and a URI. Or more on topic: tcl channels.
And these are all potential examples of subtyping relationships at work:
Tcl File -> File
HTTP URI -> URI
FTP URI -> URI
socket -> channel
file channel -> channel
Etc, etc.
-- Neil
Actually, relations can be the subject of relations. That way lies
OWL...
> Not even slightly. E.g. consider Java, where we can define exactly this
> hierarchy as subtypes without the "Kind Of" relation being reified as a
> separate type:
>
> interface Stuff {}
> interface Furniture extends Stuff {}
> interface Chair extends Furniture {}
In general, whether or not you can do this sort of thing depends on
the axiom system adopted. Subtypes are just one (common) thing that
can be adopted. But indeed, there's no need at all for relations to be
in the particular system.
Donal.
All I can say is that you are mixing up two different points that I
was trying to make.
I am not saying that subtyping cannot be used to represent subtypes or
"kind of" relationships. Never even got close to that.
My point is simple: subtyping breaks the definition of a type/class/
interface over many different files, Java is a good example regardless
of extends or implements. Both are top-down and fixed. They require
prior understanding of the similarities and relationships (the model)
before you can create the type/class/interface hierarchy. Changes are
difficult to introduce. The subtyping is a language feature and
represents a different style of programming.
That was point one.
Second point: You don't need these language features to get similar
results, maybe better results. This was the whole point of my original
"Wow, goroutines have a flat type hierarchy!" post.
Never did I say that such features do not exist or cannot model
something, maybe anything. It just isn't a very flexible development
strategy.
I also gave examples of other systems, but these were never meant to
indicate you could not model the same thing using a hierarchical type
system. They were instead examples of systems which develop from the
ground up, before any hierarchy exists.
I guess I shouldn't have ventured into the RDF terminology, but OWL is
a little closer to what I was describing, but not quite.
OWL has strict language features used to create subtypes or
subclasses. Essentially set theory. When you create the subtype, you
essentially the mathematical relationship between the classes and
establish the inferences you can make, or can't. This type of language
falls into the same category as XML-Schema types which are derived via
restriction using a fixed and known set of rules. Much easier to
understand than generic type extension which provides no guarantees.
Anyway, the relations composed of triples, where the predicate is also
an object is similar to the OWL notion of allowing type instances to
be subtypes. But the subtyping is constrained by the allowable value
space of the object. However, the subtyping is both dynamic and non-
hierarchical.
As someone who always thinks in terms of verbs and not nouns, and
interactions but not actors, the thought that the action isn't an
object, with features, seems not right. I mean that is the whole
friggin thing. The world would be pretty boring with out predicates.
> > Not even slightly. E.g. consider Java, where we can define exactly this
> > hierarchy as subtypes without the "Kind Of" relation being reified as a
> > separate type:
>
> > interface Stuff {}
> > interface Furniture extends Stuff {}
> > interface Chair extends Furniture {}
>
> In general, whether or not you can do this sort of thing depends on
> the axiom system adopted. Subtypes are just one (common) thing that
> can be adopted. But indeed, there's no need at all for relations to be
> in the particular system.
I really have nothing against this type of system, I just can't think
that far ahead. Tomorrow, I will think maybe there is Househhold Stuff
and Office Stuff. And both have Furniture which also has Chair. Now
what do I do? How do I move my Office Chair into my Home? The problem
isn't that hierarchies can't be defined, the problem is tomorrow,
yesterday's hierarchy is out of date.
Just look at the two links I provided to the Java Collection. Two
versions of Java, different hierarchy, same names.
The problem is that you're trying to make classes be the total
description of the world. The world consists of instances, and classes
are just the shadows on the wall that are cast by the instances. A
particular object, an instance, is quite capable of being a piece of
furniture (specifically, a chair) and at different times, both a
household item and an office item. Actually with a home-office, it can
be both of those latter classes simultaneously.
And yet, what is the defining characteristic of the class of Office
Stuff? Well, it's got to be that instances of the class have an
instance of the class of Offices that they belong to. The belonging-to
relation (in the sense used here) is not one that is immutable over
time, and so it is usually easier to describe the Office Stuff class
as a Rôle; a Class that is only temporarily bound to the instance.
Usually people consider classes to only be those that are inherently
characteristic of the instances; where the instance cannot stop being
a member of that class without ceasing to exist as an instance at all.
That probably ought to be a subclass of Class as a concept, but people
ambiguously mix these things up. The majority of OO languages only use
the "inherently characteristic class" concept. XOTcl and TclOO use the
broader definition (I don't know about the other Tcl object systems;
it depends on the mutability of classes and instances and that's not
something I've explored in great depth).
BTW, the difficulty of describing these things is often down to the
inherent ambiguity in natural languages. That's why ontologists use
formal vocabularies instead, where one thing can mean exactly one
thing.
> Just look at the two links I provided to the Java Collection. Two
> versions of Java, different hierarchy, same names.
Evolving a class hierarchy over time is where things get interesting.
Description logics (the foundation of ontological description) tend to
not sit well with temporal logics; IIRC, the combination of the axioms
of the two tends to make the overall intuitionistic meta-logic
intractable.
Donal.
OWL-Full, but does anyone actually use that? Second-order logics are
undecideable. OWL 2 seems to have concentrated on the DL subset only.
-- Neil
This is incorrect. There is a world of difference between the keywords
"implements" and "extends" in Java. Firstly, subtyping -- either as a
concept, or as realised in Java -- does not require you to split your
implementation over several files, or over several classes. Indeed,
subtyping says nothing about implementation whatsoever.
Secondly, subtyping does not require that the class hierarchy be fixed
ahead of time. Some less flexible statically typed languages may have
this restriction, but it by no means essential.
If your point was that *inheritance* as an implementation strategy makes
code harder to follow and potentially more fragile, then that is
something I can agree with. Indeed, that seems to be the consensus view
these days. But that is an entirely different point.
>
> That was point one.
>
> Second point: You don't need these language features to get similar
> results, maybe better results. This was the whole point of my original
> "Wow, goroutines have a flat type hierarchy!" post.
You can implement subtyping in your language from other features,
indeed, but it's still subtyping.
>
> Never did I say that such features do not exist or cannot model
> something, maybe anything. It just isn't a very flexible development
> strategy.
You did say that the real world doesn't support hierarchical models. I
directly quoted you in the previous message.
Oh, my! The base class is in one file, the derived class is in a
second file! Is this such a difficult thing go understand?
It also has nothing to do with being in different files. If you
"extend" something, you have to look back at what you are extending to
get an idea what the whole type looks like. That is okay for the
original developer, but if you are trying to understand the code, you
have to hunt around to find the full definition of what you are
looking at.
Of course this would be worse with multiple inheritance and for single
inheritance with much depth.
And even implements presents the same issues. Just reading through a
few of the manpages for the Java.util makes me ill.
> Secondly, subtyping does not require that the class hierarchy be fixed
> ahead of time. Some less flexible statically typed languages may have
> this restriction, but it by no means essential.
I'm talking about subtyping as a "language feature", once everything
is in memory who cares how it got there? Also, flexibility is "over
the lifetime of the project", not a runtime feature.
> If your point was that *inheritance* as an implementation strategy makes
> code harder to follow and potentially more fragile, then that is
> something I can agree with. Indeed, that seems to be the consensus view
> these days. But that is an entirely different point.
As a language feature, a language feature, as in "built into the
language". As in: in one place you define a class or type and then in
another place you refer to this type and bind a new type or class to
this base type using language keywords to instruct the compiler or
interpreter how to create the new type.
>
> > That was point one.
>
> > Second point: You don't need these language features to get similar
> > results, maybe better results. This was the whole point of my original
> > "Wow, goroutines have a flat type hierarchy!" post.
>
> You can implement subtyping in your language from other features,
> indeed, but it's still subtyping.
Who cares? Did I ever say that the system couldn't have subtypes? No.
Just not as a language feature. I haven't described any such feature.
> > Never did I say that such features do not exist or cannot model
> > something, maybe anything. It just isn't a very flexible development
> > strategy.
>
> You did say that the real world doesn't support hierarchical models. I
> directly quoted you in the previous message.
Right, you think "real world" includes everything, I don't. In the
real world objects can have an independent existence prior to
establishing some relationship with other objects. If the universe of
established relationships forms a hierarchy, great. But if the
modeling system places objects and classes into a pre-built hierarchy,
this does not reflect real world experience. Maybe the difference is
that in the system I'm describing you discover the hierarchy, but
there are other things besides hierarchy.
Exactly! An object (instance) can be multiple things at the same time,
or have multiple relationships at the same time (but my example
doesn't work very well, maybe a new class Location is needed to attach
directly to Chair, since the object propertied don't depend on
location. Or maybe the owner needs to be "Company X" instead of Me.
> And yet, what is the defining characteristic of the class of Office
> Stuff? Well, it's got to be that instances of the class have an
> instance of the class of Offices that they belong to. The belonging-to
> relation (in the sense used here) is not one that is immutable over
> time, and so it is usually easier to describe the Office Stuff class
> as a Rôle; a Class that is only temporarily bound to the instance.
Yes, temporarily bound, yet the system as a whole may need to
represent this temporary binding in order to represent other
relationships in the current system.
That is why the "predicate" for lack of another term also has a type/
class and you create an instance to bind the subject and object. In
other words, the predicate is not a language operator with immutable
properties.
> Usually people consider classes to only be those that are inherently
> characteristic of the instances; where the instance cannot stop being
> a member of that class without ceasing to exist as an instance at all.
> That probably ought to be a subclass of Class as a concept, but people
> ambiguously mix these things up. The majority of OO languages only use
> the "inherently characteristic class" concept. XOTcl and TclOO use the
> broader definition (I don't know about the other Tcl object systems;
> it depends on the mutability of classes and instances and that's not
> something I've explored in great depth).
The class of an object does not change, but the instance properties of
the predicate might change.
For instance, I might sell my chair to someone else. Instead of
removing the previous (Me<->Mine<->Chair) relationship, I modify the
Mine predicate to include a time interval and create a new
relationship (Me2<->Mine2<->Chair). Somewhat by accident I have
created a history of ownership of the Chair.
no Collections work fine - you can use them *without* caring about the
implementation. And the man pages for the implmentation classes are
there as well, so why are you whinging around on that point?
> But check out the last sentence: "This interface is typically used to
> pass collections around and manipulate them where maximum generality
> is desired."
>
> So basically this interface is used to avoid type checking. This is a
> perfect example of paying up front for basically the right to pay more
> later on. The very top of the collection hierarchy is advertised as a
> way to avoid all the nasty requirements imposed by this ugly system.
> Not sure if you are going to use a list or an array, a bag or a set or
> a queue or a sorted map? Just use a collection as the type.
>
exactly, and if you don't see the usefulness of that, there isn't much
else to say.
> Probably the developers are happy that their lists and bags can
> contain any type. Like wow! Dog types and Cat types in the same bag,
> oops "collection", we might need to pass this around.
Yes, they are. and if they want to restrict it further they can by
instead of using a Collection of Objects, they can have a
Collection<Cat> which will only contains Cats.
bruce
Perhaps. It's a difficult area, because when you combine description
logic (the natural model for class/object relationships) and temporal
logic (the way to characterize statements about things that change)
you get a logic that is intractable. I believe there are tractable
subsets (other than straight DL and TL), but this was an area where I
didn't pay that much attention; it's quite complex and I only really
know enough to know that this an area to be exceptionally careful (and
to call on expert help if necessary; a benefit of working in a
research university).
Donal.
In theory certain, maybe most, problems will be intractable. But the
exposed nature of the structure means that there are many
opportunities to solve specific problems. Once solved, the solution
can be applied to similar problems.
Yes, because it is wrong. Nothing in Java or other languages with
subtyping says that they have to be in different files. If you want to
do public subtyping, then the interface and the sub-type implementations
have to be in separate files, but that is just one case.
[...]
It's clear from this conversation that you are still conflating
subtyping with inheritance, and I cannot think of a more straightforward
way of explaining it, so there is little point continuing. Besides, it
seems clear also that you have retracted your initial claim that
subtyping and class hierarchies are a bad idea.
-- Neil
I just love your selective quoting of what I said to make your point.
The only point being that I don't understand something (something
which I am not even talking about).
> It's clear from this conversation that you are still conflating
> subtyping with inheritance, and I cannot think of a more straightforward
> way of explaining it, so there is little point continuing. Besides, it
> seems clear also that you have retracted your initial claim that
> subtyping and class hierarchies are a bad idea.
Again, you persist in this nonsense about what I don't understand. I'm
not trying to distinguish subtyping from inheritance.
I also never retracted any statement about subtyping and
hierarchies...how could I, according to you I don't even understand
what subtyping is.
It is amazing how you take one statement and transform it into another
using different words and claim that I used those words with your
selected meaning.
What is the purpose of doing that? I understand it is always possible
to misunderstand other people because you don't catch the meaning of
the words they have chosen, but when you intentionally put your own
words in someone elses' mouth something else is going on.
I'm sorry if you feel that I have misrepresented you. Perhaps you would
like to take this opportunity to stately clearly for the record
precisely what claims you are and are not making?
-- Neil