mboost-dp1

Når programmering skifter fra logik til gætteri


Gå til bund
Gravatar #1 - arne_v
25. jan. 2024 16:00
Programmeringssprog bør designes så der en en vis logik i dem - selvom programmøren ikke har nærlæst alle fodnoter i language spec skal betydningen af kode kunne udledes udfra en overordnet forståelse af sproget og almindelig logik. Ellers bliver programmering jo enten en gættekonkurrence eller et language spec studie.

Grimt eksempel i Java:

C:\Work>type Demo.java
public class Demo {
public static void main(String[] args) {
Integer fourHundredOnce = 400;
Integer fourHundredAgain = 400;
System.out.printf("fourHundredOnce %d == fourHundredAgain %d? %b%n", fourHundredOnce, fourHundredAgain, fourHundredOnce == fourHundredAgain);
}
}

C:\Work>javac Demo.java

C:\Work>java Demo
fourHundredOnce 400 == fourHundredAgain 400? false

C:\Work>java -XX:AutoBoxCacheMax=500 Demo
fourHundredOnce 400 == fourHundredAgain 400? true

(jeg mener at vi har haft emnet oppe før, men jeg så like en LinkedIn post hvor det kom op igen)
Gravatar #2 - larsp
25. jan. 2024 19:58
#1 I Python er == en test for equal value og "is" for samme objekt. Det undrer mig at == ikke er overloaded i java Integer objektet til at lave en value sammenligning, så de begge bliver true, ligegyldig om det er samme objekt eller ej.

Apropos stødte jeg fornylig på denne kode og tog straks en kopi i mit kode snippet arkiv:

Forcing string interning

>>> a = 'Y'*4096
>>> b = 'Y'*4096
>>> a is b
True
>>> c = 'Y'*4097
>>> d = 'Y'*4097
>>> c is d
False

Strings are interned if maximum 4096 chars, but it can be forced:

>>> import sys
>>> c = sys.intern('Y'*4097)
>>> d = sys.intern('Y'*4097)
>>> c is d
True
Gravatar #3 - arne_v
26. jan. 2024 20:45
larsp (2) skrev:

I Python er == en test for equal value og "is" for samme objekt. Det undrer mig at == ikke er overloaded i java Integer objektet til at lave en value sammenligning, så de begge bliver true, ligegyldig om det er samme objekt eller ej.
[/code]


Java understøtter ikke operator overload, så det kan ikke umiddelbart tilføjes til udvalgte klasser som Integer.

Og ændre det generelt vil bryde bagud kompabiliteten.

Givet:

Java equals ~ Grrovy == ~ Kotlin == ~ Scala ==
Java == ~ Grrovy is ~ Kotlin === ~ Scala eq

så vil jeg tro at hvis Java teamet kunne rejse 30 år tilbage i tiden ville ændre betydningen af ==.
Gravatar #4 - larsp
27. jan. 2024 07:36
arne_v (3) skrev:
Java equals ~ Grrovy == ~ Kotlin == ~ Scala ==
Java == ~ Grrovy is ~ Kotlin === ~ Scala eq

Nåh ja, man skal have fat i .equals for stringe mv. i Java.

Det minder faktisk lidt om C hvor man også skal bruge funktionskald for de mere involverede sammenligninger.

Og der er ingen operator overload overhovedet? Den slags eksisterede da i C++ på tidspunktet for Java's fødstel. Var det ud fra en idé om at lave sproget mere eksplicit og mindre overraskende?
Gravatar #5 - arne_v
27. jan. 2024 13:35
larsp (4) skrev:

Og der er ingen operator overload overhovedet?


Nej.

Groovy, Kotlin og Scala har det men ikke Java.

larsp (4) skrev:

Den slags eksisterede da i C++ på tidspunktet for Java's fødstel.


C++ er født med operator overload.

larsp (4) skrev:

Var det ud fra en idé om at lave sproget mere eksplicit og mindre overraskende?


En af de oprindelige ideer bag Java var at det skulle være simpelt.

Så Java 1.02 var et meget simpelt sprog. Langt simplere end C++.

Operator overload var en af de mange ting som C++ har men som ikke kom med i Java.

Siden er Java blevet mere kompliceret. Java 5 og Java 8 tilføjede rigtigt meget.

Men ikke operator overload.
Gravatar #6 - arne_v
27. jan. 2024 13:42
arne_v (5) skrev:

Så Java 1.02 var et meget simpelt sprog. Langt simplere end C++.

Operator overload var en af de mange ting som C++ har men som ikke kom med i Java.


Og jeg ved ikke om alle de C++ ting der blev udeladt reelt gjorde Java simplere.

Jeg køber at begrænsningen om kun implementations arv fra en klasse gør sproget simplere.

(Java 8 lavede så en lille workaround med interface default methods, men som sagt har Java ændret sig over tid)

Men jeg kan ikke se at ingen unsigned integers gør sproget simplere. Tværtimod gør det often koden mere kompleks at skal implementere unsigned logik med signed integers.
Gravatar #7 - larsp
28. jan. 2024 09:27
arne_v (6) skrev:
Men jeg kan ikke se at ingen unsigned integers gør sproget simplere. Tværtimod gør det often koden mere kompleks at skal implementere unsigned logik med signed integers.

Ja, udeladelsen af unsigned ints er da helt tosset. Det gør nærmest sproget ubrugeligt til lowlevel programmering.

Hvordan koder man binære protokoller hvor man skal udnytte unsigned integers fulde range? Jeg tænker, enten ved at arbejde med større ints og så til sidst pakke dem ned i det korrekte antal bits, eller ved at "tolerere" negative værdier og gøre hvad der skal gøres for at få det til at blive rigtigt alligevel. Afskyeligt.

Jeg så at chars er 16-bits. Vil det sige at man hænger på UTF16 til strenge, altid? Kan Java understøtte UTF8 og ASCII (nemt)?

Java virker umiddelbart som et mareridt til binære protokoller.
Gravatar #8 - arne_v
28. jan. 2024 13:26
larsp (7) skrev:

arne_v (6) skrev:

Men jeg kan ikke se at ingen unsigned integers gør sproget simplere. Tværtimod gør det often koden mere kompleks at skal implementere unsigned logik med signed integers.

Ja, udeladelsen af unsigned ints er da helt tosset. Det gør nærmest sproget ubrugeligt til lowlevel programmering.


Der er nok også andre grunde til ikke at vælge Java til lowlevel programmering.

:-)

larsp (7) skrev:

Hvordan koder man binære protokoller hvor man skal udnytte unsigned integers fulde range? Jeg tænker, enten ved at arbejde med større ints og så til sidst pakke dem ned i det korrekte antal bits, eller ved at "tolerere" negative værdier og gøre hvad der skal gøres for at få det til at blive rigtigt alligevel. Afskyeligt.


Jeg tror at det mest almindelige er at have "unsigned 8 bit" i signed 16 bit, "unsigned 16 bit" i signed 32 bit og "unsigned 32 bit" i signed 64 bit internt og så kun skrive/læse 8, 16 eller 32 bit.

Det er en komplikation. Og man har et problem med "unsigned 64 bit".

larsp (7) skrev:

Jeg så at chars er 16-bits. Vil det sige at man hænger på UTF16 til strenge, altid? Kan Java understøtte UTF8 og ASCII (nemt)?


Alle strenge i memory er UTF-16.

Det er ikke så usædvaneligt idag at køre UTF-16 eller UTF-32 internt.

Fordelen ved det fremfor UTF-8 er at det er hurtigere at finde str[ix].

Konvertering til eksternt format er ikke et problem.

PrintWriter pw = new PrintWriter(fileornetwork, "UTF-8");
pw.println(str);

og:

PrintWriter pw = new PrintWriter(fileornetwork, "US-ASCII");
pw.println(str);

gør hvad de lover.

Vil man selv håndtere lidt mere:

str.toBytes("UTF-8")

og

str.toBytes("US-ASCII")

De fleste Java implementationer understøtter et hav af encodings.
Gravatar #9 - arne_v
28. jan. 2024 14:08
larsp (7) skrev:

Java virker umiddelbart som et mareridt til binære protokoller.


Ikke godt med unsigned integers.

Men ellers er det absolut muligt.

Før Java 1.4 (2002) havde man kun DataInputStream og DataOutputStream. Og de var ikke så gode fordi de kun understøttede big endian og fordi writeObject og readObject var problematiske.


import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Gen1 {
public static void main(String[] args) throws IOException {
DataOutputStream dos = new DataOutputStream(new FileOutputStream("/Work/z1.txt"));
byte b = 0x41;
dos.writeByte(b);
short s = 0x4243;
dos.writeShort(s);
dos.close();
}
}


skriver pænt ABC ud.

Java 1.4 (2002) fik ByteBuffer hvor man selv kunne vælge endianess.


import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;

public class Gen2 {
public static void main(String[] args) throws IOException {
ByteBuffer bb = ByteBuffer.allocate(3);
bb.order(ByteOrder.LITTLE_ENDIAN);
byte b = 0x41;
bb.put(b);
short s = 0x4243;
bb.putShort(s);
bb.rewind();
FileOutputStream fos = new FileOutputStream("/Work/z2.txt");
FileChannel fc = fos.getChannel();
fc.write(bb);
fc.close();
fos.close();
}
}


skriver pænt ACB ud (little endian).

Og jeg har så mit Record library on top of ByteBuffer hvis man foretrækker OO.


import java.io.FileOutputStream;
import java.io.IOException;

import dk.vajhoej.record.Endian;
import dk.vajhoej.record.FieldType;
import dk.vajhoej.record.RecordException;
import dk.vajhoej.record.Struct;
import dk.vajhoej.record.StructField;
import dk.vajhoej.record.StructWriter;

public class Gen2X {
@Struct(endianess=Endian.LITTLE)
public static class Data {
@StructField(n=0,type=FieldType.INT1)
public byte b;
@StructField(n=1,type=FieldType.INT2)
public short s;
}
public static void main(String[] args) throws RecordException, IOException {
Data o = new Data();
o.b = 0x41;
o.s = 0x4243;
StructWriter sw = new StructWriter();
sw.write(o);
FileOutputStream fos = new FileOutputStream("/Work/z2x.txt");
fos.write(sw.getBytes());
fos.close();
}
}

Gå til top

Opret dig som bruger i dag

Det er gratis, og du binder dig ikke til noget.

Når du er oprettet som bruger, får du adgang til en lang række af sidens andre muligheder, såsom at udforme siden efter eget ønske og deltage i diskussionerne.

Opret Bruger Login