Unnavoidable Illegal Forward Reference

86 views Asked by At

I am having this issue I can't seem to resolve: I am trying to create a network of 'Location' objects. Each Location has a name and is connected to other 'adjacentLocations'. However, because it references adjacentLocations, I cannot initialize each Location Object fully because the adjacentLocations still need to be initialized.

I am coding in Java, a sample of what I mean is below:

public class Location{
    private String name;
    private Location[] adjacentLocations;

    public Location(String name, Location[] adjacentLocations){
        this.name = name;
        this.adjacentLocations = adjacentLocations;
    }
    Location bar = new Location("bar",new Location[]{townSquare, dock});
    Location townSquare = new Location("town square",new Location[]{dock, bar});
    Location dock = new Location("dock", new Location[]{bar, townSquare});
}

I do not plan on accessing the contents of the adjacent Locations until the whole "map" is initialized. I have tried putting the code in a main method, it complains that it cannot resolve symbol townSquare. I have tried declaring all the Locations and initializing within a main method, and it complains that townSquare may have not been initialized. I have tried the above code which complains illegal forward reference

I know I could try initializing all of my Locations with empty adjacent Locations and then adding them in post, but that seems like anything but elegant, and a pain in the butt. Am I missing something obvious? I tried looking up all of those error codes and did not find a useful solution to my problem.

1

There are 1 answers

0
Polygnome On BEST ANSWER

You obviously can not construct object which depend on stuff that does not yet exist. What you have created is a chicken-and-egg problem thats hard to solve in any language.

A good choice would be to manage adjacency externally, e.g. through adjacency lists:

class TownMap {
    Map<Location, List<Location>> adjacency = new HashMap<>();

    public void addLocation(Location location) {
        adjacency.putIfAbsent(location, new ArrayList());
    }

    public void addNeighbor(Location a, Location b) {
        adjacency.computeIfAbsent(a, new ArrayList<>()).add(b);
        adjacency.computeIfAbsent(b, new ArrayList<>()).add(a);
    }

    public List<Location> getNeighbours(Location location) {
        return Collections.immutableList(adjacency.get(location));
    }
}

You can of couse also initialize the adjacentLocations empty and set them later, once those adjacent locations have indeed been constructed.

You can hide the mechanism from callers by creating an interface:

public interface Location {
    public String name();
    public List<Location> neighbours(); 
}

private class LocationImpl implements Location {
    private String name;
    private List<Location> neighbours;

   protected void addNeighbour(Location location) {
        neighbours.add(location);
   }
   
   public List<Location> neighbours() {
       return Collections.immutableList(this.neighbours);
   }
   
}

public static void main(String[] args) {

    List<Location> locations = new ArrayList<>();
    LocationImpl bar = new LocationImpl("bar");
    LocationImpl docks = new LocationImpl("docks");
    LocationImpl townsquare = new LocationImpl("townsquare");
    bar.addNeighbour(docks);
    docks.setNeighbour(bar);
    // etc.

    locations.Add(bar);
    locations.add(docks);
    locations.add(townsquare);

   // give whomever you want the List<Location> which they can't manipulate further
}

With proper visibility rules and modules set up, no one can manipulate these objects further.