Add a variable to a class instance at runtime: Difference between revisions

m
→‎{{header|Wren}}: Changed to Wren S/H
m (Automated syntax highlighting fixup (second round - minor fixes))
m (→‎{{header|Wren}}: Changed to Wren S/H)
(3 intermediate revisions by 3 users not shown)
Line 340:
ELENA does not support adding a field at run-time but it can be simulated with the help of a mix-in.
 
ELENA 46.x:
<syntaxhighlight lang="elena">import extensions;
 
class Extender : BaseExtender
{
prop object foo : prop;
constructor(object)
{
this theObjectobject := object
}
}
 
public program()
{
var object := 234;
// extending an object with a field
object := new Extender(object);
 
object.foo := "bar";
 
console.printLine(object,".foo=",object.foo);
 
console.readChar()
}</syntaxhighlight>
{{out}}
Line 677:
W__OBJ2 NB. our other instance does not
|value error</syntaxhighlight>
 
=={{header|Java}}==
Adding variables to an object at runtime is not possible in Java which is a statically typed language requiring the names of all class variables to be known at compile time.
 
However, we can make it appear as though variables are being added at runtime by using a Map or similar structure.
<syntaxhighlight lang="java">
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
 
public final class AddVariableToClassInstanceAtRuntime {
 
public static void main(String[] args) {
Demonstration demo = new Demonstration();
System.out.println("Create two variables at runtime: ");
Scanner scanner = new Scanner(System.in);
for ( int i = 1; i <= 2; i++ ) {
System.out.println(" Variable number " + i + ":");
System.out.print(" Enter name: ");
String name = scanner.nextLine();
System.out.print(" Enter value: ");
String value = scanner.nextLine();
demo.runtimeVariables.put(name, value);
System.out.println();
}
scanner.close();
System.out.println("Two new runtime variables appear to have been created.");
for ( Map.Entry<String, Object> entry : demo.runtimeVariables.entrySet() ) {
System.out.println("Variable " + entry.getKey() + " = " + entry.getValue());
}
}
 
}
 
final class Demonstration {
Map<String, Object> runtimeVariables = new HashMap<String, Object>();
}
</syntaxhighlight>
{{ out }}
<pre>
Create two variables at runtime:
Variable number 1:
Enter name: Test
Enter value: 42
 
Variable number 2:
Enter name: Item
Enter value: 3.14
 
Two new runtime variables appear to have been created.
Variable Item = 3.14
Variable Test = 42
</pre>
 
=={{header|JavaScript}}==
Line 1,279 ⟶ 1,335:
 
To add a variable number of features and attributes, you can use [http://www.mozart-oz.org/documentation/base/class.html Class.new].
 
=={{header|Pascal}}==
Works with FPC (tested with version 3.2.2).
 
This could be done by playing around with the custom variants a bit.
 
Let's put the following code in a separate unit:
<syntaxhighlight lang="pascal">
unit MyObjDef;
{$mode objfpc}{$h+}{$interfaces com}
interface
 
function MyObjCreate: Variant;
 
implementation
uses
Variants, Generics.Collections;
 
var
MyObjType: TInvokeableVariantType;
 
type
IMyObj = interface
procedure SetVar(const aName: string; const aValue: Variant);
function GetVar(const aName: string): Variant;
end;
 
TMyObj = class(TInterfacedObject, IMyObj)
strict private
FMap: specialize TDictionary<string, Variant>;
public
constructor Create;
destructor Destroy; override;
procedure SetVar(const aName: string; const aValue: Variant);
function GetVar(const aName: string): Variant;
end;
 
TMyData = packed record
VType: TVarType;
Dummy1: array[0..5] of Byte;
Dummy2: Pointer;
FObj: IMyObj;
end;
 
TMyObjType = class(TInvokeableVariantType)
procedure Clear(var V: TVarData); override;
procedure Copy(var aDst: TVarData; const aSrc: TVarData; const Indir: Boolean); override;
function GetProperty(var aDst: TVarData; const aData: TVarData; const aName: string): Boolean; override;
function SetProperty(var V: TVarData; const aName: string; const aData: TVarData): Boolean; override;
end;
 
function MyObjCreate: Variant;
begin
VarClear(Result);
TMyData(Result).VType := MyObjType.VarType;
TMyData(Result).FObj := TMyObj.Create;
end;
 
constructor TMyObj.Create;
begin
FMap := specialize TDictionary<string, Variant>.Create;
end;
 
destructor TMyObj.Destroy;
begin
FMap.Free;
inherited;
end;
 
procedure TMyObj.SetVar(const aName: string; const aValue: Variant);
begin
FMap.AddOrSetValue(LowerCase(aName), aValue);
end;
 
function TMyObj.GetVar(const aName: string): Variant;
begin
if not FMap.TryGetValue(LowerCase(aName), Result) then Result := Null;
end;
 
procedure TMyObjType.Clear(var V: TVarData);
begin
TMyData(V).FObj := nil;
V.VType := varEmpty;
end;
 
procedure TMyObjType.Copy(var aDst: TVarData; const aSrc: TVarData; const Indir: Boolean);
begin
VarClear(Variant(aDst));
TMyData(aDst) := TMyData(aSrc);
end;
 
function TMyObjType.GetProperty(var aDst: TVarData; const aData: TVarData; const aName: string): Boolean;
begin
Result := True;
Variant(aDst) := TMyData(aData).FObj.GetVar(aName);
end;
 
function TMyObjType.SetProperty(var V: TVarData; const aName: string; const aData: TVarData): Boolean;
begin
Result := True;
TMyData(V).FObj.SetVar(aName, Variant(aData));
end;
 
initialization
MyObjType := TMyObjType.Create;
finalization
MyObjType.Free;
end.
</syntaxhighlight>
 
And main program:
<syntaxhighlight lang="pascal">
program test;
{$mode objfpc}{$h+}
uses
MyObjDef;
 
var
MyObj: Variant;
 
begin
MyObj := MyObjCreate;
MyObj.Answer := 42;
MyObj.Foo := 'Bar';
MyObj.When := TDateTime(34121);
WriteLn(MyObj.Answer);
WriteLn(MyObj.Foo);
//check if variable names are case-insensitive, as it should be in Pascal
WriteLn(MyObj.wHen);
end.
</syntaxhighlight>
{{out}}
<pre>
42
Bar
01.06.1993
</pre>
 
=={{header|Perl}}==
Line 1,889 ⟶ 2,082:
=={{header|Wren}}==
Although Wren is dynamically typed, it is not possible to add new variables (or fields as we prefer to call them) to a class at run time. We therefore follow the example of some of the other languages here and use a map field instead.
<syntaxhighlight lang="ecmascriptwren">import "io" for Stdin, Stdout
 
class Birds {
9,485

edits