public IObjField this[string field_name] { // TODO: 2010/04/08 // Determined that get and set BOTH need to ALWAYS auto-vivify the field. // This is because someobj["some_field"].iv = 42 calls OBJ indexer property GET, and then FIELD property SET on the field that returns. // // In future, maybe some means of avoiding "needless" auto-vivification on get can be found, // but it may be a non-critical optimization anyways -- that needs study to justify optimization effort get { if (field_name == null) { Error.BadArg("Got null field_name"); } if (!Token.is_bare_multi_word(field_name)) { Error.BadArg("Got invalid field_name '{0}'", field_name); } if (!fields.ContainsKey(field_name)) { // If the field is not present, auto-vivify the field from the Archetype's corresponding field IArchetypeField arch_field = archetype[field_name]; if (arch_field == null) { // TODO: Policy control over behavior upon .get of a field not present in the Archetype. // Default will likely be to auto-vivify and return default value? //Form1.stdout.print("ObjField.get: found null archetype field for field_name '{0}', auto-vivifying.\n", field_name); fields[field_name] = new FieldTempNull(this, field_name); // Let's see if the FieldTempNull approach works...wow, surprisingly well at near-first test! // Hmmm...if we don't have an Archetype field to get an IObjField from, how do we know what type to instantiate? // Seems it will have to be fatal? I'd rather be able to auto-vivify, but this gets called _before_ the .set ...argh... //Error.Throw("Somehow got null archetype arch_field for field_name '{0}'", field_name); } else { fields[field_name] = arch_field.default_value; // TODO: Verify that this is a "deep" copy, or deep enough at any rate... } } return(fields[field_name]); } set { if (field_name == null) { Error.BadArg("Got null field_name"); } if (!Token.is_bare_multi_word(field_name)) { Error.BadArg("Got invalid field_name '{0}'", field_name); } if (archetype[field_name] != null) { SemanticTypes type_of_new_field = value.type.semantic_type; SemanticTypes type_of_arch_field = archetype[field_name].type.semantic_type; if (type_of_new_field != type_of_arch_field) { Error.BadArg("ObjField.set: Called for Obj '{0}' with Archetype '{1}' on field_name '{2}', " + "with strange IObjField having semantic type '{3}' " + "which differs from the archetype field semantic type '{4}'", autotag, archetype.tag, field_name, type_of_new_field, type_of_arch_field); } } //else //{ // Form1.stdout.print("Obj.this[].set called for field '{0}', archetype does not contain that field\n", field_name); //} if (fields.ContainsKey(field_name) && fields[field_name].type != FieldType.EMPTY) { // Call to set for an already-present field. // This is OK if the already-present field is a FieldTempNull... ??? // TODO: Should be controlled by a policy variable. // A likely default would be to warn and replace the existing attribute. Error.BadArg("Got already-present Obj parse_field_name '{0}'", field_name); } fields[field_name] = value; } } // this[field_name]
public IObjField this[string field_name] { // TODO: 2010/04/08 // Determined that get and set BOTH need to ALWAYS auto-vivify the field. // This is because someobj["some_field"].iv = 42 calls OBJ indexer property GET, and then FIELD property SET on the field that returns. // // In future, maybe some means of avoiding "needless" auto-vivification on get can be found, // but it may be a non-critical optimization anyways -- that needs study to justify optimization effort get { if (field_name == null) { Error.BadArg("Got null field_name"); } if (!Token.is_bare_multi_word(field_name)) { Error.BadArg("Got invalid field_name '{0}'", field_name); } if (!fields.ContainsKey(field_name)) { // If the field is not present, auto-vivify the field from the Archetype's corresponding field IArchetypeField arch_field = archetype[field_name]; if (arch_field == null) { // TODO: Policy control over behavior upon .get of a field not present in the Archetype. // Default will likely be to auto-vivify and return default value? //Form1.stdout.print("ObjField.get: found null archetype field for field_name '{0}', auto-vivifying.\n", field_name); fields[field_name] = new FieldTempNull(this, field_name); // Let's see if the FieldTempNull approach works...wow, surprisingly well at near-first test! // Hmmm...if we don't have an Archetype field to get an IObjField from, how do we know what type to instantiate? // Seems it will have to be fatal? I'd rather be able to auto-vivify, but this gets called _before_ the .set ...argh... //Error.Throw("Somehow got null archetype arch_field for field_name '{0}'", field_name); } else { fields[field_name] = arch_field.default_value; // TODO: Verify that this is a "deep" copy, or deep enough at any rate... } } return fields[field_name]; } set { if (field_name == null) { Error.BadArg("Got null field_name"); } if (!Token.is_bare_multi_word(field_name)) { Error.BadArg("Got invalid field_name '{0}'", field_name); } if (archetype[field_name] != null) { SemanticTypes type_of_new_field = value.type.semantic_type; SemanticTypes type_of_arch_field = archetype[field_name].type.semantic_type; if (type_of_new_field != type_of_arch_field) { Error.BadArg("ObjField.set: Called for Obj '{0}' with Archetype '{1}' on field_name '{2}', " + "with strange IObjField having semantic type '{3}' " + "which differs from the archetype field semantic type '{4}'", autotag, archetype.tag, field_name, type_of_new_field, type_of_arch_field); } } //else //{ // Form1.stdout.print("Obj.this[].set called for field '{0}', archetype does not contain that field\n", field_name); //} if (fields.ContainsKey(field_name) && fields[field_name].type != FieldType.EMPTY) { // Call to set for an already-present field. // This is OK if the already-present field is a FieldTempNull... ??? // TODO: Should be controlled by a policy variable. // A likely default would be to warn and replace the existing attribute. Error.BadArg("Got already-present Obj parse_field_name '{0}'", field_name); } fields[field_name] = value; } }