JS vs Java - dynamic typing

by: Ethan McCue

Conversation with somebody#0002

So as far as JS and Java are concerned the syntaxes of the two languages are very similar but the semantics between the two vary wildly even discounting browser weirdness.

but for simple things it's very similar. small algorithms and things like that

For simple things all languages are similar

okay, so here's a bet. I will write a bit of javascript code. very small, very simple.

You will try to write some mock Java that does the same thing.

I bet that you will find it harder to do

function upperCaseName(entity) {
    return {...entity, name: entity.name.toUpperCase() }
}

const dog = { name: "Fido", favorite_toy: "Squeeks" }
const person { name: "Bob", majored_in: "Physics" , age: 30 }

upperCaseName(dog) //  { name: "FIDO", favorite_toy: "Squeeks" }
upperCaseName(person) // { name: "BOB", majored_in: "Physics" , age: 30 }

Objects are a JS-specific thing, but... that should be doable in Java. won't look nice, won't behave well, but it'll be doable

oh so the thing that most libraries in JS use as their primary data representation are JS specific?

yes

in Java you'd use a POD for them

in JS you don't want that overhead, in Java it's kinda unavoidable

POD?

plain old data

You mean a class with getters and setters right? That won't work here.

Dynamic languages have a whole set of design patterns unique to their inherit flexibility in the same way Functional Languages like Haskell have a whole set of design patterns unique to their inherit restrictions.

Javascript is dynamic and weakly typed and Java is static and strongly typed. The second bit there is very important because it clues to the underlying semantics of the language.

yeah, of course.

also kinda working in Java:

import java.util.Map;
import java.util.HashMap;

public class Main {
  public static void main(String[] args) {
      System.out.println(upperCaseName(new HashMap<String, Object>() {{ put("name", "Fido"); put("favorite_toy", "Squeeks"); }}));
  }

  static Map<String, Object> upperCaseName(Map<String, Object> map) {
      if (map.containsKey("name") && map.get("name") instanceof String) {
          map.put("name", ((String) map.get("name")).toUpperCase());
      }
      return map;
  }
}

In Javascript saying class has an insanely different meaning than in Javascript.

In java when you say class you are declaring a template for a concrete object to be created later. You are saying that your object will have these slots, that your object will have these methods that will work on said slots of data, and you define how the object will be constructed.

But in Javascript you aren't doing that. In Javascript you are actually creating an object.

That object is the "prototype" for new objects to be created from and you are saying "hey just copy this object"

that's the prototype, not the class

There is no such thing as the class Not in any form that isn't syntax sugar.

The main similarity between JS and Java is the syntax, which was done on purpose. Hence the misleading name of JavaScript.

The whole point was to look like Have at first glance but at its core JS is more a badly implemented lisp than anything else.

Now I am going to do the dog example in idiomatic java give me a few minutes

import java.util.Objects;

interface HasName<T extends HasName<T>> {
    String getName();
    T withName(String name);
}

class Dog implements HasName<Dog> {
    private final String name;
    private final String favoriteToy;

    Dog(String name, String favoriteToy) {
        Objects.requireNonNull(name, "Name should not be null");
        Objects.requireNonNull(favoriteToy, "Favorite Toy should not be null");
        this.name = name;
        this.favoriteToy = favoriteToy;
    }

    @Override
    public String getName() {
        return this.name;
    }

    @Override
    public Dog withName(String name) {
        return new Dog(name, this.favoriteToy);
    }

    public String getFavoriteToy() {
        return this.favoriteToy;
    }

    public Dog withFavoriteToy(String favoriteToy) {
        return new Dog(this.name, favoriteToy);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Dog dog = (Dog) o;
        return Objects.equals(name, dog.name) &&
                Objects.equals(favoriteToy, dog.favoriteToy);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, favoriteToy);
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", favoriteToy='" + favoriteToy + '\'' +
                '}';
    }
}

class Person implements HasName<Person> {
    private String name;
    private String majoredIn;
    private int age;

    Person(String name, String majoredIn, int age) {
        Objects.requireNonNull(name, "Name should not be null");
        Objects.requireNonNull(majoredIn, "Majored In should not be null");
        this.name = name;
        this.majoredIn = majoredIn;
        this.age = age;
    }

    @Override
    public String getName() {
        return this.name;
    }

    @Override
    public Person withName(String name) {
        return new Person(name, this.majoredIn, this.age);
    }

    public String getMajoredIn() {
        return this.majoredIn;
    }

    public Person withMajoredIn(String majoredIn) {
        return new Person(this.name, majoredIn, this.age);
    }

    public int getAge() {
        return this.age;
    }

    public Person withAge(int age) {
        return new Person(this.name, this.majoredIn, age);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age &&
                Objects.equals(name, person.name) &&
                Objects.equals(majoredIn, person.majoredIn);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, majoredIn, age);
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", majoredIn='" + majoredIn + '\'' +
                ", age=" + age +
                '}';
    }
}


public class Main {
    private static <T extends HasName<T>> T upperCaseName(HasName<T> entity) {
        return entity.withName(entity.getName().toUpperCase());
    }

    public static void main(String[] args) {
        Dog fido = new Dog("Fido", "Squeeks");
        Person bob = new Person("Bob", "Physics", 30);
        System.out.println("Before:");
        System.out.println(fido);
        System.out.println(bob);

        Dog fidoUpper = upperCaseName(fido);
        Person bobUpper = upperCaseName(bob);

        System.out.println("After:");
        System.out.println(fidoUpper);
        System.out.println(bobUpper);
    }
}

<- Index