Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.java.programmer > #35750 > unrolled thread

Re: double == double

Started byEric Sosman <esosman@comcast-dot-net.invalid>
First post2016-10-12 09:39 -0400
Last post2016-10-20 15:01 +0200
Articles 20 on this page of 47 — 6 participants

Back to article view | Back to comp.lang.java.programmer

This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by below is the oldest one visible, not the original post.


Contents

  Re: double == double Eric Sosman <esosman@comcast-dot-net.invalid> - 2016-10-12 09:39 -0400
    Re: double == double Michael Jung <miju@golem.phantasia.org> - 2016-10-13 21:10 +0200
      Re: double == double Michael Jung <miju@golem.phantasia.org> - 2016-10-15 14:04 +0200
        Re: double == double Eric Sosman <esosman@comcast-dot-net.invalid> - 2016-10-15 09:13 -0400
          Re: double == double Arne Vajhøj <arne@vajhoej.dk> - 2016-10-15 10:32 -0400
            Re: double == double Eric Sosman <esosman@comcast-dot-net.invalid> - 2016-10-15 10:46 -0400
              Re: double == double Michael Jung <miju@golem.phantasia.org> - 2016-10-15 17:44 +0200
              Re: double == double 4ndre4 <626401fd-4bc7-4f8f-b641-563ae0f72920@626401fd-4bc7-4f8f-b641-563ae0f72920.invalid> - 2016-10-15 17:36 +0100
                Re: double == double Eric Sosman <esosman@comcast-dot-net.invalid> - 2016-10-15 14:15 -0400
                  Re: double == double 4ndre4 <626401fd-4bc7-4f8f-b641-563ae0f72920@626401fd-4bc7-4f8f-b641-563ae0f72920.invalid> - 2016-10-15 19:41 +0100
              Re: double == double Arne Vajhøj <arne@vajhoej.dk> - 2016-10-15 20:39 -0400
        Re: double == double Arne Vajhøj <arne@vajhoej.dk> - 2016-10-15 10:41 -0400
          Re: double == double 4ndre4 <626401fd-4bc7-4f8f-b641-563ae0f72920@626401fd-4bc7-4f8f-b641-563ae0f72920.invalid> - 2016-10-15 23:09 +0100
            Re: double == double Eric Sosman <esosman@comcast-dot-net.invalid> - 2016-10-15 18:28 -0400
              Re: double == double 4ndre4 <626401fd-4bc7-4f8f-b641-563ae0f72920@626401fd-4bc7-4f8f-b641-563ae0f72920.invalid> - 2016-10-16 03:13 +0100
                Re: double == double Eric Sosman <esosman@comcast-dot-net.invalid> - 2016-10-16 08:37 -0400
                  Re: double == double 4ndre4 <626401fd-4bc7-4f8f-b641-563ae0f72920@626401fd-4bc7-4f8f-b641-563ae0f72920.invalid> - 2016-10-16 14:06 +0100
            Re: double == double Arne Vajhøj <arne@vajhoej.dk> - 2016-10-15 20:30 -0400
              Re: double == double 4ndre4 <626401fd-4bc7-4f8f-b641-563ae0f72920@626401fd-4bc7-4f8f-b641-563ae0f72920.invalid> - 2016-10-16 03:16 +0100
                Re: double == double 4ndre4 <626401fd-4bc7-4f8f-b641-563ae0f72920@626401fd-4bc7-4f8f-b641-563ae0f72920.invalid> - 2016-10-16 03:18 +0100
                Re: double == double Arne Vajhøj <arne@vajhoej.dk> - 2016-10-16 09:45 -0400
                  Re: double == double 4ndre4 <626401fd-4bc7-4f8f-b641-563ae0f72920@626401fd-4bc7-4f8f-b641-563ae0f72920.invalid> - 2016-10-16 14:51 +0100
                    Re: double == double Arne Vajhøj <arne@vajhoej.dk> - 2016-10-16 11:24 -0400
                      Re: double == double 4ndre4 <626401fd-4bc7-4f8f-b641-563ae0f72920@626401fd-4bc7-4f8f-b641-563ae0f72920.invalid> - 2016-10-16 16:43 +0100
                        Re: double == double Arne Vajhøj <arne@vajhoej.dk> - 2016-10-16 12:54 -0400
                          Re: double == double 4ndre4 <626401fd-4bc7-4f8f-b641-563ae0f72920@626401fd-4bc7-4f8f-b641-563ae0f72920.invalid> - 2016-10-16 18:37 +0100
                            Re: double == double Arne Vajhøj <arne@vajhoej.dk> - 2016-10-16 14:14 -0400
                              Re: double == double 4ndre4 <626401fd-4bc7-4f8f-b641-563ae0f72920@626401fd-4bc7-4f8f-b641-563ae0f72920.invalid> - 2016-10-16 22:19 +0100
                                Re: double == double Arne Vajhøj <arne@vajhoej.dk> - 2016-10-16 22:49 -0400
                                  Re: double == double a.laforgia@gmail.com - 2016-10-17 01:53 -0700
                                    Re: double == double Patrick Roemer <sangamon@netcologne.de> - 2016-10-17 19:04 +0200
                                      Re: double == double 4ndre4 <626401fd-4bc7-4f8f-b641-563ae0f72920@626401fd-4bc7-4f8f-b641-563ae0f72920.invalid> - 2016-10-17 20:17 +0100
                                        Re: double == double Patrick Roemer <sangamon@netcologne.de> - 2016-10-17 23:11 +0200
                                          Re: double == double 4ndre4 <626401fd-4bc7-4f8f-b641-563ae0f72920@626401fd-4bc7-4f8f-b641-563ae0f72920.invalid> - 2016-10-17 22:46 +0100
                                            Re: double == double Patrick Roemer <sangamon@netcologne.de> - 2016-10-18 18:55 +0200
                                              Re: double == double 4ndre4 <626401fd-4bc7-4f8f-b641-563ae0f72920@626401fd-4bc7-4f8f-b641-563ae0f72920.invalid> - 2016-10-18 18:52 +0100
                                                Re: double == double Patrick Roemer <sangamon@netcologne.de> - 2016-10-20 15:03 +0200
                                          True O-O [Was: double == double] Eric Sosman <esosman@comcast-dot-net.invalid> - 2016-10-17 18:06 -0400
                                            Re: True O-O Patrick Roemer <sangamon@netcologne.de> - 2016-10-18 18:32 +0200
                                            Re: True O-O [Was: double == double] Arne Vajhøj <arne@vajhoej.dk> - 2016-10-19 22:09 -0400
                                    Re: double == double Arne Vajhøj <arne@vajhoej.dk> - 2016-10-19 21:58 -0400
                                  Re: double == double Patrick Roemer <sangamon@netcologne.de> - 2016-10-17 18:58 +0200
                                    Re: double == double 4ndre4 <626401fd-4bc7-4f8f-b641-563ae0f72920@626401fd-4bc7-4f8f-b641-563ae0f72920.invalid> - 2016-10-17 20:32 +0100
                                      Re: double == double Patrick Roemer <sangamon@netcologne.de> - 2016-10-17 23:21 +0200
                                      Re: double == double Arne Vajhøj <arne@vajhoej.dk> - 2016-10-19 21:38 -0400
                                    Re: double == double Arne Vajhøj <arne@vajhoej.dk> - 2016-10-19 21:47 -0400
                                      Re: double == double Patrick Roemer <sangamon@netcologne.de> - 2016-10-20 15:01 +0200

Page 2 of 3 — ← Prev page 1 [2] 3  Next page →


#35783

FromArne Vajhøj <arne@vajhoej.dk>
Date2016-10-16 09:45 -0400
Message-ID<nu00a0$5sj$1@gioia.aioe.org>
In reply to#35778
On 10/15/2016 10:16 PM, 4ndre4 wrote:
> On 16/10/2016 01:30, Arne Vajhøj wrote:
> [...]
>> = is fine for String. But < <= > >= can be problematic:
>
> I know well, but - as said in my previous post - I am assuming that the
> comparator would parse the version and carry out a correct comparison on
> its single parts. Similarly to having a sstring representing a date.
> It's not that strings are problematic to represent strings; you have to
> parse those strings correctly.

Yes.

But that model is really using a dedicated class to represent
the item and all comparisons should be done on instances of
that class and String is just an external representation used
outside of Java.

Arne




[toc] | [prev] | [next] | [standalone]


#35784

From4ndre4 <626401fd-4bc7-4f8f-b641-563ae0f72920@626401fd-4bc7-4f8f-b641-563ae0f72920.invalid>
Date2016-10-16 14:51 +0100
Message-ID<nu00ks$edh$5@dont-email.me>
In reply to#35783
On 16/10/2016 14:45, Arne Vajhøj wrote:

[...]
> But that model

Sorry, which model?

-- 
4ndre4

[toc] | [prev] | [next] | [standalone]


#35785

FromArne Vajhøj <arne@vajhoej.dk>
Date2016-10-16 11:24 -0400
Message-ID<nu063a$edp$1@gioia.aioe.org>
In reply to#35784
On 10/16/2016 9:51 AM, 4ndre4 wrote:
> On 16/10/2016 14:45, Arne Vajhøj wrote:
>
> [...]
>> But that model
>
> Sorry, which model?

The model for dates in Java which you seem to suggest for version numbers.

Arne

[toc] | [prev] | [next] | [standalone]


#35786

From4ndre4 <626401fd-4bc7-4f8f-b641-563ae0f72920@626401fd-4bc7-4f8f-b641-563ae0f72920.invalid>
Date2016-10-16 16:43 +0100
Message-ID<nu075n$4cs$1@dont-email.me>
In reply to#35785
On 16/10/2016 16:24, Arne Vajhøj wrote:

[...]
> The model for dates in Java which you seem to suggest for version numbers.

Sorry, you seem to miss the point here (or maybe it's me?)

You stated that you don't think that double nor String are good choices 
for version numbers.

There's no logical reason to believe that, IMO.

Strings are as good as double for version numbers, as long as you know 
the semantics of your values and hence you know how to process them.

Your StringVersion and DoubleVersion classes, for example, could 
implement Comparator<T> and its compare() and equals() methods.

I don't see why that would be a problem.

The only reason I would not use a double for a version number is 
because, on a general principle, I don't like using inherently imprecise 
data structures to represent precise information.

-- 
4ndre4

[toc] | [prev] | [next] | [standalone]


#35787

FromArne Vajhøj <arne@vajhoej.dk>
Date2016-10-16 12:54 -0400
Message-ID<nu0bcj$nbt$1@gioia.aioe.org>
In reply to#35786
On 10/16/2016 11:43 AM, 4ndre4 wrote:
> On 16/10/2016 16:24, Arne Vajhøj wrote:
>
> [...]
>> The model for dates in Java which you seem to suggest for version
>> numbers.
>
> Sorry, you seem to miss the point here (or maybe it's me?)
>
> You stated that you don't think that double nor String are good choices
> for version numbers.
>
> There's no logical reason to believe that, IMO.
>
> Strings are as good as double for version numbers, as long as you know
> the semantics of your values and hence you know how to process them.

But using String comparison does not work at all.

Using a Version class can have the right semantics. But then it is
no longer a String that is the version.

> Your StringVersion and DoubleVersion classes, for example, could
> implement Comparator<T> and its compare() and equals() methods.
>
> I don't see why that would be a problem.

You could have String carrying the version data and then
put all the methods working on the data in a VersionProcessor
class.

But I tend to like OO principles. And the above would be
about as non-OO'ish as something can be.

Arne

[toc] | [prev] | [next] | [standalone]


#35788

From4ndre4 <626401fd-4bc7-4f8f-b641-563ae0f72920@626401fd-4bc7-4f8f-b641-563ae0f72920.invalid>
Date2016-10-16 18:37 +0100
Message-ID<nu0dsb$kv3$3@dont-email.me>
In reply to#35787
On 16/10/2016 17:54, Arne Vajhøj wrote:

[...]
> But using String comparison does not work at all.

I am not talking about string comparison. I am talking about specific 
comparison semantics that has to be implemented ad hoc.

> Using a Version class can have the right semantics. But then it is
> no longer a String that is the version.

Okay, so your point was that using string comparison (not the type 
String in itself) is not a good idea for versions; in which case I 
agree. It sounded a bit different though. Using String to represent a 
version and implement the right semantics for comparison is totally 
sensible.

> But I tend to like OO principles. And the above would be
> about as non-OO'ish as something can be.

Not at all. Sorry - maybe it's my limit - but I don't see anything wrong 
with the following - do you?

         List<Version> versions = new ArrayList<>();

         versions.add(new Version("1.9.0-123"));
         versions.add(new Version("1.10.0-123"));
         versions.add(new Version("1.7.0-123"));
         versions.add(new Version("1.7.0-10"));
         versions.add(new Version("1.7.0-9"));

         Collections.sort(versions);

         for (Version version : versions) {
             System.out.println(version);
         }

Output:
1.7.0-9
1.7.0-10
1.7.0-123
1.7.0-123
1.9.0-123
1.10.0-123

....

     static class Version implements Comparable<Version> {
         private static Pattern PATTERN = Pattern.compile(
                   "(\\d+)\\.(\\d+)\\.(\\d+)-(\\d+)");
         private final ParsedVersion version;
         private final String versionAsString;

         class ParsedVersion {
             int major;
             int minor;
             int patch;
             int build;

             boolean lessThan(ParsedVersion other) {
                 return major < other.major
                         || minor < other.minor
                         || patch < other.patch
                         || build < other.build;
             }
         }

         Version(String versionAsString) throws InvalidVersionException {
             this.versionAsString = versionAsString;
             this.version = parse();
         }

         public int compareTo(Version other) {
             if (versionAsString.equals(other.versionAsString)) return 0;
             if (version.lessThan(other.version)) return -1;
             return 1;
         }

         @Override
         public String toString() {
             return versionAsString;
         }

         private ParsedVersion parse() throws InvalidVersionException {
             Matcher matcher = PATTERN.matcher(versionAsString);
             if (!matcher.find()) {
                 throw new InvalidVersionException(versionAsString);
             }
             ParsedVersion parsedVersion = new ParsedVersion();
             parsedVersion.major = Integer.valueOf(matcher.group(1));
             parsedVersion.minor = Integer.valueOf(matcher.group(2));
             parsedVersion.patch = Integer.valueOf(matcher.group(3));
             parsedVersion.build = Integer.valueOf(matcher.group(4));
             return parsedVersion;
         }
     }

-- 
4ndre4

[toc] | [prev] | [next] | [standalone]


#35790

FromArne Vajhøj <arne@vajhoej.dk>
Date2016-10-16 14:14 -0400
Message-ID<nu0g1b$vt5$2@gioia.aioe.org>
In reply to#35788
On 10/16/2016 1:37 PM, 4ndre4 wrote:
> On 16/10/2016 17:54, Arne Vajhøj wrote:
>
> [...]
>> But using String comparison does not work at all.
>
> I am not talking about string comparison. I am talking about specific
> comparison semantics that has to be implemented ad hoc.
>
>> Using a Version class can have the right semantics. But then it is
>> no longer a String that is the version.
>
> Okay, so your point was that using string comparison (not the type
> String in itself) is not a good idea for versions; in which case I
> agree. It sounded a bit different though. Using String to represent a
> version and implement the right semantics for comparison is totally
> sensible.
>
>> But I tend to like OO principles. And the above would be
>> about as non-OO'ish as something can be.
>
> Not at all. Sorry - maybe it's my limit - but I don't see anything wrong
> with the following - do you?

>     static class Version implements Comparable<Version> {
>         private static Pattern PATTERN = Pattern.compile(
>                   "(\\d+)\\.(\\d+)\\.(\\d+)-(\\d+)");
>         private final ParsedVersion version;
>         private final String versionAsString;
>
>         class ParsedVersion {
>             int major;
>             int minor;
>             int patch;
>             int build;
>
>             boolean lessThan(ParsedVersion other) {
>                 return major < other.major
>                         || minor < other.minor
>                         || patch < other.patch
>                         || build < other.build;
>             }
>         }
>
>         Version(String versionAsString) throws InvalidVersionException {
>             this.versionAsString = versionAsString;
>             this.version = parse();
>         }
>
>         public int compareTo(Version other) {
>             if (versionAsString.equals(other.versionAsString)) return 0;
>             if (version.lessThan(other.version)) return -1;
>             return 1;
>         }
>
>         @Override
>         public String toString() {
>             return versionAsString;
>         }
>
>         private ParsedVersion parse() throws InvalidVersionException {
>             Matcher matcher = PATTERN.matcher(versionAsString);
>             if (!matcher.find()) {
>                 throw new InvalidVersionException(versionAsString);
>             }
>             ParsedVersion parsedVersion = new ParsedVersion();
>             parsedVersion.major = Integer.valueOf(matcher.group(1));
>             parsedVersion.minor = Integer.valueOf(matcher.group(2));
>             parsedVersion.patch = Integer.valueOf(matcher.group(3));
>             parsedVersion.build = Integer.valueOf(matcher.group(4));
>             return parsedVersion;
>         }
>     }

Nothing wrong with that code.

But that code is not using String as version - it is using a
Version class as version - and that Version class has the ability
to convert to and from String.

Arne


[toc] | [prev] | [next] | [standalone]


#35791

From4ndre4 <626401fd-4bc7-4f8f-b641-563ae0f72920@626401fd-4bc7-4f8f-b641-563ae0f72920.invalid>
Date2016-10-16 22:19 +0100
Message-ID<nu0qtc$eiu$1@dont-email.me>
In reply to#35790
On 16/10/2016 19:14, Arne Vajhøj wrote:

[...]
> But that code is not using String as version

Erm... how about this? :) I don't see how this is less OO-ish than the 
previous one, but hey... okay!...:

         List<String> versions = new ArrayList<String>();

         versions.add("1.9.0-123");
         versions.add("1.10.0-123");
         versions.add("1.7.0-123");
         versions.add("1.7.0-123");
         versions.add("1.7.0-10");
         versions.add("1.7.0-9");

         Collections.sort(versions, new VersionComparator());

...

static class VersionComparator implements Comparator<String> {
         private static Pattern PATTERN = Pattern.compile(
                     "(\\d+)\\.(\\d+)\\.(\\d+)-(\\d+)");

         class ParsedVersion {
             int major;
             int minor;
             int patch;
             int build;

             boolean lessThan(ParsedVersion other) {
                 return major < other.major
                         || minor < other.minor
                         || patch < other.patch
                         || build < other.build;
             }
         }

         public int compare(String version1, String version2) {
             try {
                 ParsedVersion pv1 = parse(version1);
                 ParsedVersion pv2 = parse(version2);
                 if (pv1.equals(pv2)) return 0;
                 if (pv1.lessThan(pv2)) return -1;
                 return 1;
             } catch (InvalidVersionException e) {
                 throw new IllegalArgumentException(e);
             }
         }

         private ParsedVersion parse(String versionAsString)
                throws InvalidVersionException {
             Matcher matcher = PATTERN.matcher(versionAsString);
             if (!matcher.find()) {
                 throw new InvalidVersionException(versionAsString);
             }
             ParsedVersion parsedVersion = new ParsedVersion();
             parsedVersion.major = Integer.valueOf(matcher.group(1));
             parsedVersion.minor = Integer.valueOf(matcher.group(2));
             parsedVersion.patch = Integer.valueOf(matcher.group(3));
             parsedVersion.build = Integer.valueOf(matcher.group(4));
             return parsedVersion;
         }
     }



-- 
4ndre4

[toc] | [prev] | [next] | [standalone]


#35792

FromArne Vajhøj <arne@vajhoej.dk>
Date2016-10-16 22:49 -0400
Message-ID<nu1e88$9gn$1@gioia.aioe.org>
In reply to#35791
On 10/16/2016 5:19 PM, 4ndre4 wrote:
> On 16/10/2016 19:14, Arne Vajhøj wrote:
>
> [...]
>> But that code is not using String as version
>
> Erm... how about this? :) I don't see how this is less OO-ish than the
> previous one, but hey... okay!...:
>
>         List<String> versions = new ArrayList<String>();
>
>         versions.add("1.9.0-123");
>         versions.add("1.10.0-123");
>         versions.add("1.7.0-123");
>         versions.add("1.7.0-123");
>         versions.add("1.7.0-10");
>         versions.add("1.7.0-9");
>
>         Collections.sort(versions, new VersionComparator());
>
> ...
>
> static class VersionComparator implements Comparator<String> {

>         public int compare(String version1, String version2) {
>             try {
>                 ParsedVersion pv1 = parse(version1);
>                 ParsedVersion pv2 = parse(version2);
>                 if (pv1.equals(pv2)) return 0;
>                 if (pv1.lessThan(pv2)) return -1;
>                 return 1;
>             } catch (InvalidVersionException e) {
>                 throw new IllegalArgumentException(e);
>             }
>         }

Having data and methods operating on the data separate is
very non-OO'ish in my book.

Arne



[toc] | [prev] | [next] | [standalone]


#35796

Froma.laforgia@gmail.com
Date2016-10-17 01:53 -0700
Message-ID<be7ba475-196e-4269-8b6e-e4a88f8305f1@googlegroups.com>
In reply to#35792
On Monday, 17 October 2016 03:51:55 UTC+1, Arne Vajhøj  wrote:

[...]
> Having data and methods operating on the data separate is
> very non-OO'ish in my book.

That's a kind of purist approach that I find very little pragmatic. Having methods that act on data is how OO is normally implemented.

This:

        double d1 = 3.4;
        double d2 = 5.6;
        double dMax = Math.max(d1, d2);

is certainly better than this:

    class PairOfDoubles {
        double d1;
        double d2;

        public PairOfDoubles(double d1, double d2) {
            this.d1 = d1;
            this.d2 = d2;
        }

        public double max() {
            return d1 >= d2 ? d1 : d2;
        }
    }

[toc] | [prev] | [next] | [standalone]


#35802

FromPatrick Roemer <sangamon@netcologne.de>
Date2016-10-17 19:04 +0200
Message-ID<nu30a0$j0r$1@newsreader4.netcologne.de>
In reply to#35796
Responding to a.laforgia@gmail.com:
> On Monday, 17 October 2016 03:51:55 UTC+1, Arne Vajhøj  wrote:
>> Having data and methods operating on the data separate is
>> very non-OO'ish in my book.
> 
> That's a kind of purist approach that I find very little pragmatic. Having methods that act on data is how OO is normally implemented.
> 
> This:
> 
>         double d1 = 3.4;
>         double d2 = 5.6;
>         double dMax = Math.max(d1, d2);
> 
> is certainly better than this:
> 
>     class PairOfDoubles {
>         double d1;
>         double d2;
> 
>         public PairOfDoubles(double d1, double d2) {
>             this.d1 = d1;
>             this.d2 = d2;
>         }
> 
>         public double max() {
>             return d1 >= d2 ? d1 : d2;
>         }
>     }

Doubles are not objects in Java, which may be considered a flaw in the
language itself from an OO point of view, so it's a bit problematic to
use them in a discussion of good OO design.

In other OO (or hybrid) languages the max API looks different than in
Java, and the Java way would likely be considered "non-OO". Take Scala,...

scala> 1.23.max(3.14)
res0: Double = 3.14

...Smalltalk,...

st> 1.23 max: 3.14
3.14

...or, kind of an outlier, Ruby.

irb(main):001:0> [1.23, 3.14].max
=> 3.14

"Normally" one might add the operation to the type itself in Java, as
well. Exceptions are multiple possible implementations given a single
type (e.g. when choosing Comparator over Comparable), 3rd party classes
one cannot extend with new methods, or simply lack of objects to get all
OO about at all (your example).

Best regards,
Patrick

[toc] | [prev] | [next] | [standalone]


#35803

From4ndre4 <626401fd-4bc7-4f8f-b641-563ae0f72920@626401fd-4bc7-4f8f-b641-563ae0f72920.invalid>
Date2016-10-17 20:17 +0100
Message-ID<nu382t$pf6$1@dont-email.me>
In reply to#35802
On 17/10/2016 18:04, Patrick Roemer wrote:

> Doubles are not objects in Java, which may be considered a flaw in the
> language itself from an OO point of view, so it's a bit problematic to
> use them in a discussion of good OO design.

Well, replace double with Double in my example. It won't change the 
conclusions.

-- 
4ndre4

[toc] | [prev] | [next] | [standalone]


#35805

FromPatrick Roemer <sangamon@netcologne.de>
Date2016-10-17 23:11 +0200
Message-ID<nu3eq2$tv6$1@newsreader4.netcologne.de>
In reply to#35803
Responding to 4ndre4:
> On 17/10/2016 18:04, Patrick Roemer wrote:
> 
>> Doubles are not objects in Java, which may be considered a flaw in the
>> language itself from an OO point of view, so it's a bit problematic to
>> use them in a discussion of good OO design.
> 
> Well, replace double with Double in my example. It won't change the 
> conclusions.

It would not change any conclusions, but it would be utterly besides the
point, as well.

The claim was that the Java Math.max() implementation is an example of
"how OO is normally implemented". I have given three examples of other
OO languages where the #max() operation is attached to an object. I'd
consider this the "normal" OO pattern. Java is the odd one out here. I
argue that this is not because the Java designers did "better OO" than
the others, but rather because they were doing no OO at all, lacking any
objects to orient around when working with doubles. In other cases, with
objects readily available, they would do "normal" OO, just looking
at Object#equals(), for example.

In OO, one usually sends messages to objects, which triggers operations
on their encapsulated state. Java's Math.max() is not how OO is
"normally" done in my book.

Best regards,
Patrick

[toc] | [prev] | [next] | [standalone]


#35807

From4ndre4 <626401fd-4bc7-4f8f-b641-563ae0f72920@626401fd-4bc7-4f8f-b641-563ae0f72920.invalid>
Date2016-10-17 22:46 +0100
Message-ID<nu3gr1$8g8$2@dont-email.me>
In reply to#35805
On 17/10/2016 22:11, Patrick Roemer wrote:

[...]
> The claim was that the Java Math.max() implementation is an example of
> "how OO is normally implemented".

By "how OO is normally implemented" I meant having methods that act on 
data, which is exactly what happens within a class. I admit that the 
max() example was unfortunate.

The problem is where encapsulation stops. If you have a class C 
containing data D and methods M that act on those data:

C:
    D
    M(D)

within C you have the same problem: a procedural model.

This is what happens in many OO languages and it's accepted as normal.

It can also be seen as one of the many reasons a class' responsibility 
should be very limited.

I wish we were able to define "domain" types just as with databases: if 
you need a 'Money' type, you create a type based on a more primitive 
type (BCD decimal with 15 digits, of which 4 decimal, for example). At 
that point, you can declare columns of that type. The 'Money' type would 
not *contain* a BCD decimal, it would actually *be* a BCD decimal, with 
its own validation rules. In Java, instead, you'd only have a Money 
class wrapping around a BigDecimal, and handle the BigDecimal inside, 
with a procedural approach.

But I am rambling now :)

-- 
4ndre4

[toc] | [prev] | [next] | [standalone]


#35810

FromPatrick Roemer <sangamon@netcologne.de>
Date2016-10-18 18:55 +0200
Message-ID<nu5k5q$a8e$1@newsreader4.netcologne.de>
In reply to#35807
Responding to 4ndre4:
> The problem is where encapsulation stops. If you have a class C 
> containing data D and methods M that act on those data:
> 
> C:
>     D
>     M(D)
> 
> within C you have the same problem: a procedural model.
> 
> This is what happens in many OO languages and it's accepted as normal.

It should rather be: C holds a reference to another object D, and its
methods trigger sending messages to D. There still is (or at least can
be) encapsulation of D's state, and, as opposed to the procedural
approach, there's late binding - the behavior invoked by a message send
depends on the type and state of D. As shown in the Smalltalk/Scala/Ruby
examples, the illusion of OO-ness can be maintained down to primitives
like doubles. There is no data, it's objects all the way down. ;)

Best regards,
Patrick

[toc] | [prev] | [next] | [standalone]


#35811

From4ndre4 <626401fd-4bc7-4f8f-b641-563ae0f72920@626401fd-4bc7-4f8f-b641-563ae0f72920.invalid>
Date2016-10-18 18:52 +0100
Message-ID<nu5ngh$7ki$1@dont-email.me>
In reply to#35810
On 18/10/2016 17:55, Patrick Roemer wrote:

[...]
> It should rather be: C holds a reference to another object D, and its
> methods trigger sending messages to D.

Let's say you have a 'Person' class that holds an object of type 
'Email'. How should the class 'Email' be defined if not as something 
that contains a string and methods (e.g. validation) that act on that 
string? You can encapsulate and encapsulate, but then you stop at a 
procedural level. I can't see any other solution with the main OO 
languages today (C++, Java, Python).

-- 
4ndre4

[toc] | [prev] | [next] | [standalone]


#35850

FromPatrick Roemer <sangamon@netcologne.de>
Date2016-10-20 15:03 +0200
Message-ID<nuafa9$eop$2@newsreader4.netcologne.de>
In reply to#35811
Responding to 4ndre4:
> On 18/10/2016 17:55, Patrick Roemer wrote:
>> It should rather be: C holds a reference to another object D, and its
>> methods trigger sending messages to D.
> 
> Let's say you have a 'Person' class that holds an object of type 
> 'Email'. How should the class 'Email' be defined if not as something 
> that contains a string and methods (e.g. validation) that act on that 
> string?

Last time I checked, Strings were objects with methods in Java, so
C ~ Email, D ~ String.

Validation methods don't seem to make much sense on an Email object -
should be named PerhapsAnEmail, otherwise.

Best regards,
Patrick

[toc] | [prev] | [next] | [standalone]


#35808 — True O-O [Was: double == double]

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2016-10-17 18:06 -0400
SubjectTrue O-O [Was: double == double]
Message-ID<nu3hvn$ss8$1@dont-email.me>
In reply to#35805
On 10/17/2016 5:11 PM, Patrick Roemer wrote:
>
> In OO, one usually sends messages to objects, which triggers operations
> on their encapsulated state. Java's Math.max() is not how OO is
> "normally" done in my book.

     As someone who is most definitely not a dyed-in-the-wool O-O Expert,
I'd be interested to hear your opinion of things like, say

	Collections.sort(theList);

vs.

	theList.sortYourself();  // fictional, today

It seems fairly normal to me that some operations are "built into" the
classes, while others are "imposed from without," although the criteria
for choosing between the approaches may not always be perfectly clear.
This is especially true of operations not anticipated at design time;
I can more easily imagine adding a

	Collections.getMedianElement(theCollection);  // fictional

than I can imagine adding a

	theCollection.getMedianElement();  // fictional

to every Collection subclass.

     What's the Righteous O-O Way here?  Drag out more interfaces?

	interface SortableList<T> extends List<T> {
	    void sortYourself();
	}

	interface MedianAwareCollection<T> extends Collection<T> {
	    T getMedianElement();
	}

	...

That doesn't seem very attractive, as one would need to keep in mind
which of the various Lists are or are not also SortableLists.  Sure, we
have Set and SortedSet (and we know that TreeSet implements both while
HashSet implements only Set), but I imagine that things would soon get
out of hand with the addition of BinarySearchable and Reversible and
Rotatable and Shufflable and ...

-- 
esosman@comcast-dot-net.invalid
"Don't be afraid of work. Make work afraid of you." -- TLM

[toc] | [prev] | [next] | [standalone]


#35809 — Re: True O-O

FromPatrick Roemer <sangamon@netcologne.de>
Date2016-10-18 18:32 +0200
SubjectRe: True O-O
Message-ID<nu5iq5$9b3$1@newsreader4.netcologne.de>
In reply to#35808
Responding to Eric Sosman:
> On 10/17/2016 5:11 PM, Patrick Roemer wrote:
>>
>> In OO, one usually sends messages to objects, which triggers operations
>> on their encapsulated state. Java's Math.max() is not how OO is
>> "normally" done in my book.
> 
>      As someone who is most definitely not a dyed-in-the-wool O-O Expert,
> I'd be interested to hear your opinion of things like, say

I'm by no means an OO expert (and certainly not an OO zealot), but I'll
bite... :)

To start with, I'm as confused as anybody regarding a sound definition
of OO, but here's one I like that Stefan Ram got from Alan Kay - I hope
he didn't make it up. ;)

"OOP to me means only messaging, local retention and protection and
hiding of state-process, and extreme late-binding of all things. It can
be done in Smalltalk and in LISP. There are possibly other systems in
which this is possible, but I'm not aware of them."
http://www.purl.org/stefan_ram/pub/doc_kay_oop_en

> 	Collections.sort(theList);
> 
> vs.
> 
> 	theList.sortYourself();  // fictional, today

Smalltalk:

st> x
(2 3 1 )
st> x asSortedCollection
SortedCollection (1 2 3 )
st> x
(2 3 1 )
st> x sort
(1 2 3 )
st> x
(1 2 3 )

We can get a sorted copy or ask the collection to sort itself in-place,
both through messages to the collection. Doesn't seem to be a problem in
itself.

> It seems fairly normal to me that some operations are "built into" the
> classes, while others are "imposed from without," although the criteria
> for choosing between the approaches may not always be perfectly clear.

I'd think that "builtin vs imposed from without" is mostly orthogonal to
"message sends vs function calls". Example from this thread: A
Comparator imposes an ordering strategy from without, but we still
message an object and behavior is bound late - pretty in line with the
above definition.

> This is especially true of operations not anticipated at design time;
> I can more easily imagine adding a
> 
> 	Collections.getMedianElement(theCollection);  // fictional
> 
> than I can imagine adding a
> 
> 	theCollection.getMedianElement();  // fictional
> 
> to every Collection subclass.

"More easily" doesn't sound like a design criterion but more like a
trade-off consideration given Java and its standard library as it is
today. That's perfectly reasonable, but it's not supporting the question
which approach represents a better (OO) design, it's more of a
counter-force.

Could an implementation perhaps go to AbstractList or a default method?

Let's try this in Scala:

<snip>
patrick@milgrim:/work/git/other/scala/scala$ git diff
diff --git a/src/library/scala/collection/SeqLike.scala
b/src/library/scala/collection/SeqLike.scala
index 2d66225..041a87c 100644
--- a/src/library/scala/collection/SeqLike.scala
+++ b/src/library/scala/collection/SeqLike.scala
@@ -679,6 +679,13 @@ trait SeqLike[+A, +Repr] extends Any with
IterableLike[A, Repr] with GenSeqLike[
   /* Need to override string, so that it's not the Function1's string
that gets mixed in.
    */
   override def toString = super[IterableLike].toString
+
+  def median(): Option[A] =
+    if(isEmpty)
+      None
+    else
+      Some(apply(size / 2))
+
 }

 /** The companion object for trait `SeqLike`.
patrick@milgrim:/work/git/other/scala/scala$ build/pack/bin/scala
Welcome to Scala 2.12.0-20161014-083346-933bab2 (Java HotSpot(TM) 64-Bit
Server VM, Java 1.8.0_73).
Type in expressions for evaluation. Or try :help.

scala> Seq(1,2,3).median()
res0: Option[Int] = Some(2)

scala> Array(1,2,3).median()
res1: Option[Int] = Some(2)

scala> Vector(1,2,3).median()
res2: Option[Int] = Some(2)

scala> scala.collection.immutable.Queue(1,2,3).median()
res3: Option[Int] = Some(2)
</snip>

This may be plain wrong (I'm not that familiar with the internals of the
Scala collection zoo), but it gives some hope that it might be done
right with limited effort.

So in principle it should be possible to add a median method to the
collection hierarchy. If trade-off considerations speak against it,
that's probably due to design decisions in the Java language and
standard library, not because going for the static function would be the
right choice OO-wise.

That all being said, I'd think that this method might be too special
purpose for the generic Collection API.

>      What's the Righteous O-O Way here?

Very likely it involves having an object (the collection itself or
another) that reacts to a message by computing and passing the median
element. :) It may very well differ from the Righteous Java way. (And
I wouldn't claim that the Righteous OO way is always desirable.) I
just think that one should try to distinguish arguments based on "pure
principles" (of any paradigm) from those based on idiosyncrasies of a
specific language design. It's perfectly fine to mix and weigh them in a
concrete discussion, but one should always be clear about which is
which. And this didn't seem to be the case with the Math#max() example
at all.

There probably is a way to do good OO. There probably is a way to do
good Java. There may be a way to do good OO in Java. There may even be a
way to do good Programming. And each of these ways will conflict with
each other, more often than one would expect. :)

Best regards,
Patrick

[toc] | [prev] | [next] | [standalone]


#35844 — Re: True O-O [Was: double == double]

FromArne Vajhøj <arne@vajhoej.dk>
Date2016-10-19 22:09 -0400
SubjectRe: True O-O [Was: double == double]
Message-ID<nu98vt$h9o$1@gioia.aioe.org>
In reply to#35808
On 10/17/2016 6:06 PM, Eric Sosman wrote:
> On 10/17/2016 5:11 PM, Patrick Roemer wrote:
>>
>> In OO, one usually sends messages to objects, which triggers operations
>> on their encapsulated state. Java's Math.max() is not how OO is
>> "normally" done in my book.
>
>     As someone who is most definitely not a dyed-in-the-wool O-O Expert,
> I'd be interested to hear your opinion of things like, say
>
>     Collections.sort(theList);
>
> vs.
>
>     theList.sortYourself();  // fictional, today
>
> It seems fairly normal to me that some operations are "built into" the
> classes, while others are "imposed from without," although the criteria
> for choosing between the approaches may not always be perfectly clear.
> This is especially true of operations not anticipated at design time;
> I can more easily imagine adding a
>
>     Collections.getMedianElement(theCollection);  // fictional
>
> than I can imagine adding a
>
>     theCollection.getMedianElement();  // fictional
>
> to every Collection subclass.
>
>     What's the Righteous O-O Way here?  Drag out more interfaces?
>
>     interface SortableList<T> extends List<T> {
>         void sortYourself();
>     }
>
>     interface MedianAwareCollection<T> extends Collection<T> {
>         T getMedianElement();
>     }
>
>     ...
>
> That doesn't seem very attractive, as one would need to keep in mind
> which of the various Lists are or are not also SortableLists.  Sure, we
> have Set and SortedSet (and we know that TreeSet implements both while
> HashSet implements only Set), but I imagine that things would soon get
> out of hand with the addition of BinarySearchable and Reversible and
> Rotatable and Shufflable and ...

All true.

But I think somewhat besides the point.

Classes work on other classes all the time.

But the Version as String was a lot more than that.

The String type did not contain any information about the format
and how it could and should be processed.

The list send over is an interface and Collections are
(I assume) using the public methods of that interface.

The Comparator had to have explicit knowledge about the format
of the String with version info to process it.

In that sense it is more like if Collections.sort used
reflection to get the actual type and if it was an ArrayList
then it used reflection to get the array behind.

That would be bad.

Collections.sort should not know about how a common
List implementation stores its internal data.

Just like a Version Comparator should not know about
string formats.

Arne


[toc] | [prev] | [next] | [standalone]


Page 2 of 3 — ← Prev page 1 [2] 3  Next page →

Back to top | Article view | comp.lang.java.programmer


csiph-web