concept G22Variable extends ConceptWithChangeListeners is IPersistenceInfo, AutoCloseable { settableWithVar S name; volatile O value; settableWithVar bool persistent; // dispose of resource when project is closed // or variable is deleted/overwritten settable bool autoClose; // big = value is stored in separate file settableWithVar bool big; transient Lock loadLock = lock(); // field "value" is persisted iff field "persistent" is set public Map _persistenceInfo() { ret litmap(value := persistent && !big); } public transient simplyCached FieldVar varValue() { ret new FieldVar(this, "value", () -> value(), value -> value(value)); } void setValueIfNull(O defaultValue) { if (defaultValue != null && value == null) value(defaultValue); } O cachedValue() { ret value; } O get aka value() { if (value != null) ret value; if (big) ret getBigValue(); ret value; } O getOnce() { if (value != null) ret value; if (big) ret loadBigValueImpl(); ret value; } G22Utils g22utils() { ret main g22utils(this); } File bigFile() { ret newFile(assertNotNull(g22utils().projectDir()), id + "-" + sanitizeFileName(name) + ".structgz"); } O getBigValue() { O o; { lock loadLock; o = loadBigValueImpl(); setValueField(o); } g22utils().bigVariableLoaded(this); ret o; } O loadBigValueImpl() { ret unstructureGZFile(bigFile(), g22utils().classFinder()); } void setBigValue(O value) { if (value == null) { if (hasBigValue()) { deleteBigValue(); change(); } } else { unload(); File f = bigFile(); saveGZStructureToFile(f, value); change(); } } void deleteBigValue() { deleteFile(bigFile()); } bool hasBigValue() { ret fileExists(bigFile()); } void makeBig { if (big) ret; setBigValue(value); big(true); persistent(true); } void makeSmall { if (!big) ret; get(); // will cache the value big(false); deleteBigValue(); } selfType value aka setValue aka set(O o) { if (big) setBigValue(o); else if (!eq(value, o)) { setValueField(o); change(); } this; } // Always overwrite even if eq to old value selfType set_force(O o) { if (big) setBigValue(o); else { setValueField(o); change(); } this; } bool notNull aka has() { ret big ? hasBigValue() : value != null; } void unload() { if (big) setValueField(null); } O setValueField(O o) { if (autoClose && o != value) dispose value; ret value = o; } close { if (autoClose) dispose value; } void delete :: before { close(); } void changeInsideOfValue { if (big) value(value); change(); } void clear { set(null); } selfType makePersistent() { ret persistent(true); } }