Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.java.programmer > #35750 > unrolled thread
| Started by | Eric Sosman <esosman@comcast-dot-net.invalid> |
|---|---|
| First post | 2016-10-12 09:39 -0400 |
| Last post | 2016-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.
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 →
| From | Arne Vajhøj <arne@vajhoej.dk> |
|---|---|
| Date | 2016-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]
| From | 4ndre4 <626401fd-4bc7-4f8f-b641-563ae0f72920@626401fd-4bc7-4f8f-b641-563ae0f72920.invalid> |
|---|---|
| Date | 2016-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]
| From | Arne Vajhøj <arne@vajhoej.dk> |
|---|---|
| Date | 2016-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]
| From | 4ndre4 <626401fd-4bc7-4f8f-b641-563ae0f72920@626401fd-4bc7-4f8f-b641-563ae0f72920.invalid> |
|---|---|
| Date | 2016-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]
| From | Arne Vajhøj <arne@vajhoej.dk> |
|---|---|
| Date | 2016-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]
| From | 4ndre4 <626401fd-4bc7-4f8f-b641-563ae0f72920@626401fd-4bc7-4f8f-b641-563ae0f72920.invalid> |
|---|---|
| Date | 2016-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]
| From | Arne Vajhøj <arne@vajhoej.dk> |
|---|---|
| Date | 2016-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]
| From | 4ndre4 <626401fd-4bc7-4f8f-b641-563ae0f72920@626401fd-4bc7-4f8f-b641-563ae0f72920.invalid> |
|---|---|
| Date | 2016-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]
| From | Arne Vajhøj <arne@vajhoej.dk> |
|---|---|
| Date | 2016-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]
| From | a.laforgia@gmail.com |
|---|---|
| Date | 2016-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]
| From | Patrick Roemer <sangamon@netcologne.de> |
|---|---|
| Date | 2016-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]
| From | 4ndre4 <626401fd-4bc7-4f8f-b641-563ae0f72920@626401fd-4bc7-4f8f-b641-563ae0f72920.invalid> |
|---|---|
| Date | 2016-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]
| From | Patrick Roemer <sangamon@netcologne.de> |
|---|---|
| Date | 2016-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]
| From | 4ndre4 <626401fd-4bc7-4f8f-b641-563ae0f72920@626401fd-4bc7-4f8f-b641-563ae0f72920.invalid> |
|---|---|
| Date | 2016-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]
| From | Patrick Roemer <sangamon@netcologne.de> |
|---|---|
| Date | 2016-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]
| From | 4ndre4 <626401fd-4bc7-4f8f-b641-563ae0f72920@626401fd-4bc7-4f8f-b641-563ae0f72920.invalid> |
|---|---|
| Date | 2016-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]
| From | Patrick Roemer <sangamon@netcologne.de> |
|---|---|
| Date | 2016-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]
| From | Eric Sosman <esosman@comcast-dot-net.invalid> |
|---|---|
| Date | 2016-10-17 18:06 -0400 |
| Subject | True 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]
| From | Patrick Roemer <sangamon@netcologne.de> |
|---|---|
| Date | 2016-10-18 18:32 +0200 |
| Subject | Re: 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]
| From | Arne Vajhøj <arne@vajhoej.dk> |
|---|---|
| Date | 2016-10-19 22:09 -0400 |
| Subject | Re: 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