Crack`s std.lib

6 views
Skip to first unread message

bazhenovc

unread,
Apr 26, 2011, 1:21:59 PM4/26/11
to crack-lang-dev
Hello!

I`ve got a few comments about crack.lang.Object.

It contains virtual oper init(), oper del() and virtual oper bind(),
oper release(). oper release() internally uses oper del(). I suggest
making oper bind and oper release final, to avoid possible problems
occur on overriding these opers.

isTrue() and toBool() are virtually identical, however IMHO having
both of them is a bit obsolete:)

int cmp(Object other) and >,<,<=,>= operators. I think that they are
incorrect in the context of an Object. For example - if we have a
Button and a TextBox then how do we determine which one is bigger? I
think that it should be bool cmp(...), that returns true if both
objects are equal.

Arno Rehn

unread,
Apr 26, 2011, 1:59:17 PM4/26/11
to crack-l...@googlegroups.com
On Tuesday 26 April 2011 19:21:59 bazhenovc wrote:
> int cmp(Object other) and >,<,<=,>= operators. I think that they are
> incorrect in the context of an Object. For example - if we have a
> Button and a TextBox then how do we determine which one is bigger? I
> think that it should be bool cmp(...), that returns true if both
> objects are equal.
Agreed in that they don't make sense for Object itself. I'd just have a bool
equals(Object other) and int hashCode() (maybe we already have that). The
default implementation of equals would then be this.hashCode() ==
that.hashCode().
For stuff like cmp(...) we should have a seperate
interface/class/trait/whatever like Comparable or Ordered.

--
Arno Rehn
ar...@arnorehn.de

bazhenovc

unread,
Apr 26, 2011, 3:34:33 PM4/26/11
to crack-lang-dev
WIll this offer be accepted?
> a...@arnorehn.de

Michael Muller

unread,
Apr 26, 2011, 4:46:17 PM4/26/11
to bazhenovc, crack-lang-dev

bazhenovc wrote:
> Hello!
>
> I`ve got a few comments about crack.lang.Object.
>
> It contains virtual oper init(), oper del() and virtual oper bind(),
> oper release(). oper release() internally uses oper del(). I suggest
> making oper bind and oper release final, to avoid possible problems
> occur on overriding these opers.

oper bind() and oper release() are already implicitly final - they have to be
because they can be called on a null value. Although, this doesn't appear to
be documented in the manual, I'll fix that.

>
> isTrue() and toBool() are virtually identical, however IMHO having
> both of them is a bit obsolete:)

toBool() is a final type conversion operator - again, it exists and is final
so we can use a null value as a boolean. isTrue() is its virtual counterpart,
it allows derived classes to override whether a value is true or false. For
example, Buffer (the base class of String) overrides it to make an empty
buffer false and a non-empty buffer true. In general, Crack follows Lisp-like
semantics - empty is false, non-empty is true, zero is false, non-zero is
true...

>
> int cmp(Object other) and >,<,<=,>= operators. I think that they are
> incorrect in the context of an Object. For example - if we have a
> Button and a TextBox then how do we determine which one is bigger? I

The default behavior is to compare by pointer value, so if the Button is at
address 100 and the TextBox is at address 200, the TextBox is greater. This
is a useful behavior for example in the case of tree keys - having it lets us
use arbitrary types as the key and still fall through to a well-defined
comparison behavior.

> think that it should be bool cmp(...), that returns true if both
> objects are equal.

That would reverse the semantics of languages like C and python (see C's
strcmp() function and python's __cmp__() method).

The advantage of the cmp() over a specific equality check is that all of the
comparison operators (>, <, ==, !=, >= and <=) can be implemented as final
functions in terms of the cmp() virtual function. So any class can implement
the entire comparison suite by simply implementing cmp().

BTW, I stole this particular bit of awesomeness from Python :-)

=============================================================================
michaelMuller = mmu...@enduden.com | http://www.mindhog.net/~mmuller
-----------------------------------------------------------------------------
Scnozwangers? Vermicious Knids? What kind of rubbish is that?
- Mr. Salt, "Willy Wonka and the Chocolate Factory"
=============================================================================

Michael Muller

unread,
Apr 26, 2011, 5:09:16 PM4/26/11
to Arno Rehn, crack-l...@googlegroups.com

Arno Rehn wrote:
> On Tuesday 26 April 2011 19:21:59 bazhenovc wrote:
> > int cmp(Object other) and >,<,<=,>= operators. I think that they are
> > incorrect in the context of an Object. For example - if we have a
> > Button and a TextBox then how do we determine which one is bigger? I
> > think that it should be bool cmp(...), that returns true if both
> > objects are equal.
> Agreed in that they don't make sense for Object itself. I'd just have a bool
> equals(Object other) and int hashCode() (maybe we already have that). The
> default implementation of equals would then be this.hashCode() ==
> that.hashCode().

We don't have hashCode(), but we probably should. I wouldn't want equality
defined in terms of hash code because of the generally small possibility of
hash collisions.

> For stuff like cmp(...) we should have a seperate
> interface/class/trait/whatever like Comparable or Ordered.

Why do you think it should be separated out from Object?

>
> --
> Arno Rehn
> ar...@arnorehn.de

Michael Muller

unread,
Apr 26, 2011, 5:21:31 PM4/26/11
to bazhenovc, crack-lang-dev

Michael Muller wrote:
>
> bazhenovc wrote:
> > Hello!
> >
> > I`ve got a few comments about crack.lang.Object.
> >
> > It contains virtual oper init(), oper del() and virtual oper bind(),
> > oper release(). oper release() internally uses oper del(). I suggest
> > making oper bind and oper release final, to avoid possible problems
> > occur on overriding these opers.
>
> oper bind() and oper release() are already implicitly final - they have to be
> because they can be called on a null value. Although, this doesn't appear to
> be documented in the manual, I'll fix that.
>
> >
> > isTrue() and toBool() are virtually identical, however IMHO having
> > both of them is a bit obsolete:)
>
> toBool() is a final type conversion operator - again, it exists and is final
> so we can use a null value as a boolean. isTrue() is its virtual counterpart,
> it allows derived classes to override whether a value is true or false. For
> example, Buffer (the base class of String) overrides it to make an empty
> buffer false and a non-empty buffer true. In general, Crack follows Lisp-like
> semantics - empty is false, non-empty is true, zero is false, non-zero is
> true...

I forgot to mention: toBool() will be replaced with the more general "oper to"
conversion operator syntax. That is, it will eventually be defined as "oper
to bool() {... }"

If you are not willing to control your own mind, there are plenty of other
people who are willing to do it for you.
=============================================================================

Arno Rehn

unread,
Apr 27, 2011, 8:27:16 AM4/27/11
to crack-l...@googlegroups.com
On Tuesday 26 April 2011 23:09:16 Michael Muller wrote:
> Arno Rehn wrote:
> > On Tuesday 26 April 2011 19:21:59 bazhenovc wrote:
> > > int cmp(Object other) and >,<,<=,>= operators. I think that they are
> > > incorrect in the context of an Object. For example - if we have a
> > > Button and a TextBox then how do we determine which one is bigger? I
> > > think that it should be bool cmp(...), that returns true if both
> > > objects are equal.
> >
> > Agreed in that they don't make sense for Object itself. I'd just have a
> > bool equals(Object other) and int hashCode() (maybe we already have
> > that). The default implementation of equals would then be
> > this.hashCode() == that.hashCode().
>
> We don't have hashCode(), but we probably should. I wouldn't want equality
> defined in terms of hash code because of the generally small possibility of
> hash collisions.
>
> > For stuff like cmp(...) we should have a seperate
> > interface/class/trait/whatever like Comparable or Ordered.
>
> Why do you think it should be separated out from Object?
Because there is no 'less-than' or 'greater-than' relation defined in terms of
general objects. What should cmp(...) return when it compares two non-equal
objects? -1? 1? Neither makes much sense to me.
I like the way Scala handles these things, that's why I proposed a Ordered
(Scala) or Comparable (.NET I think) trait.

--
Arno Rehn
ar...@arnorehn.de

Michael Muller

unread,
Apr 27, 2011, 9:54:29 AM4/27/11
to crack-l...@googlegroups.com
On Wed, Apr 27, 2011 at 8:27 AM, Arno Rehn <ar...@arnorehn.de> wrote:
> On Tuesday 26 April 2011 23:09:16 Michael Muller wrote:
>> Arno Rehn wrote:
>> > On Tuesday 26 April 2011 19:21:59 bazhenovc wrote:
>> > > int cmp(Object other) and >,<,<=,>= operators. I think that they are
>> > > incorrect in the context of an Object. For example - if we have a
>> > > Button and a TextBox then how do we determine which one is bigger? I
>> > > think that it should be bool cmp(...), that returns true if both
>> > > objects are equal.
>> >
>> > Agreed in that they don't make sense for Object itself. I'd just have a
>> > bool equals(Object other) and int hashCode() (maybe we already have
>> > that). The default implementation of equals would then be
>> > this.hashCode() == that.hashCode().
>>
>> We don't have hashCode(), but we probably should.  I wouldn't want equality
>> defined in terms of hash code because of the generally small possibility of
>> hash collisions.
>>
>> > For stuff like cmp(...) we should have a seperate
>> > interface/class/trait/whatever like Comparable or Ordered.
>>
>> Why do you think it should be separated out from Object?
> Because there is no 'less-than' or 'greater-than' relation defined in terms of
> general objects. What should cmp(...) return when it compares two non-equal
> objects? -1? 1? Neither makes much sense to me.

As I explained earlier, there is: it's based on the address at which the
object resides. So the a.cmp(b) returns 0 if "a is b", 1 if the address of
a > address of b, and -1 otherwise.

I'm willing to reconsider this in light of a more pragmatic argument, like if
there's something that you can do better with a separate Comparable interface.

Offhand, there are two flaws that I can think of with the current approach:

1) it makes it harder to define classes that want to specialize the comparison
operators separately.
2) it relies on a virtual function call, so it makes it harder for classes
that make heavy use of it to implement efficiently.

Concerning 1, I can't think of a reason why someone would want to do this that
doesn't break the "a > b" means "b < a" assertion. I would argue that
breaking this
assertion is a bad practice, and while I'm not looking to explicitly
disallow bad
practices in Crack, I certainly don't want to change my design to accommodate
them.

Concerning 2, there are features that I hope to add to the language that fix
this.

From what I can see, having a separate Comparable interface solves neither of
these.

Shannon Weyrick

unread,
Apr 27, 2011, 11:42:01 AM4/27/11
to crack-l...@googlegroups.com

So is it a compile-time error in these languages to try to compare two
objects that aren't Comparable?

FWIW, I'd also like to hear about the benefits of a different interface,
but I'm otherwise on board with our current implementation.

Shannon

Arno Rehn

unread,
Apr 27, 2011, 12:24:40 PM4/27/11
to crack-l...@googlegroups.com
Correct.

> FWIW, I'd also like to hear about the benefits of a different interface,
> but I'm otherwise on board with our current implementation.

I simply think it's not useful and doesn't make much sense. < and > should
fill a very specific role: comparing two objects.

Common sense tells us that we can't compare everything in terms of < and >. I
don't know if an egg is less than a chicken. It might be smaller, but then we
are comparing sizes. It might be 'younger', but then we are comparing ages. It
might even taste better, but then we are comparing taste. However, simply
doing 'if (chicken < egg) { .. }' is not predictable in any way and I don't
see what problem it could possibly solve.
Therefore I'd leave it to the people to provide sensible implementations.

--
Arno Rehn
ar...@arnorehn.de

bazhenovc

unread,
Apr 27, 2011, 1:05:16 PM4/27/11
to crack-lang-dev
Also do not forget about distributed objects - it is definitely
incorrect to compare them by their address:)

On 27 апр, 19:24, Arno Rehn <a...@arnorehn.de> wrote:
> On Wednesday 27 April 2011 17:42:01 Shannon Weyrick wrote:> On 04/27/2011 09:54 AM, Michael Muller wrote:
> > > On Wed, Apr 27, 2011 at 8:27 AM, Arno Rehn<a...@arnorehn.de>  wrote:
> > >> I like the way Scala handles these things, that's why I proposed a
> > >> Ordered (Scala) or Comparable (.NET I think) trait.
>
> > So is it a compile-time error in these languages to try to compare two
> > objects that aren't Comparable?
>
> Correct.
>
> > FWIW, I'd also like to hear about the benefits of a different interface,
> > but I'm otherwise on board with our current implementation.
>
> I simply think it's not useful and doesn't make much sense. < and > should
> fill a very specific role: comparing two objects.
>
> Common sense tells us that we can't compare everything in terms of < and >. I
> don't know if an egg is less than a chicken. It might be smaller, but then we
> are comparing sizes. It might be 'younger', but then we are comparing ages. It
> might even taste better, but then we are comparing taste. However, simply
> doing 'if (chicken < egg) { .. }' is not predictable in any way and I don't
> see what problem it could possibly solve.
> Therefore I'd leave it to the people to provide sensible implementations.
>
> --
> Arno Rehn
> a...@arnorehn.de

Shannon Weyrick

unread,
Apr 27, 2011, 2:26:59 PM4/27/11
to crack-l...@googlegroups.com
It's incorrect to compare a theoretical simple Int class by address as
well - that's why you'd override the cmp() method to handle the proper
logic for that class. Presumably you'd do the same with the base class
of some distributed object. If you didn't, it would default to comparing
the local memory addresses of your two distributed objects (i.e. even if
it's "distributed", the script still has a local representation in
memory of each). Admittedly I haven't worked with distributed objects,
but I don't see how the current system limits this - am I missing something?

The most convincing thing I've heard so far in the case for a different
cmp() system is the compile time error for uncomparable objects. It's
hard for me to come up with a convincing scenario where that turns out
to be really useful, though.

bazhenovc

unread,
Apr 27, 2011, 2:44:07 PM4/27/11
to crack-lang-dev
And we still arrive at the need to override the default behavior:)
However in case of having virtual cmp() method it will be a bit
slower.

In practice, we will override it for most classes, because there are
very few places, where pointer comparsion would benefit(and there we
can implement it as usual, using mixin or macro with no virtual
method).

Shannon Weyrick

unread,
Apr 27, 2011, 3:13:14 PM4/27/11
to crack-l...@googlegroups.com
Ok so it seems the argument is more that there's no use in having a
slower (because virtual) default cmp() in base Object, because (almost)
any class that needs it will have to implement it's own cmp() anyway,
and it can do so in a faster way?

bazhenovc

unread,
Apr 27, 2011, 3:26:08 PM4/27/11
to crack-lang-dev
Roughly speaking yes. Also, as Arno Rehn mentioned, this is not
intuitive/logically correct.
Reply all
Reply to author
Forward
0 new messages