PBXB64 OOP & Classes
OOP & Classes
Standard
Full object-oriented programming with CLASS, INTERFACE, METHOD, PROPERTY, EVENTS FROM, EVENTS END, RAISEEVENT, IMPLEMENTS, and WITH. Multi-subscriber event dispatch, interface inheritance, and property accessors. All backed by real vtable and event-helper runtime code.
CLASS with METHOD and PROPERTY
Class definition and usage
#COMPILE EXE
#DIM ALL
CLASS MyClass
INSTANCE count AS LONG
CLASS METHOD Create() ' constructor, runs when the object is created
count = 0
END METHOD
INTERFACE IMyClass
INHERIT IUNKNOWN
METHOD Increment() AS LONG
count = count + 1
METHOD = count
END METHOD
PROPERTY GET Counter() AS LONG
PROPERTY = count
END PROPERTY
END INTERFACE
END CLASS
FUNCTION PBMAIN() AS LONG
LOCAL obj AS IMyClass
LET obj = CLASS "MyClass"
obj.Increment()
obj.Increment()
PRINT "Count: "; obj.Counter ' 2
FUNCTION = 0
END FUNCTION
CLASS defines a type with INSTANCE variables and an INTERFACE that holds the METHOD and PROPERTY members. Objects are created with LET obj = CLASS "name"; CLASS METHOD Create() acts as the constructor. Members are called via dot notation (methods with or without parentheses) with real vtable dispatch.
EVENTS FROM / EVENTS END / RAISEEVENT
Multi-subscriber events
#COMPILE EXE
#DIM ALL
INTERFACE IEvents ' event interface: the shared contract
INHERIT IUNKNOWN
METHOD MyEvent(BYVAL iValue AS LONG)
END INTERFACE
CLASS Listener1 AS EVENT ' event sinks are marked AS EVENT
INTERFACE IEvents
INHERIT IUNKNOWN
AS EVENT
METHOD MyEvent(BYVAL iValue AS LONG)
PRINT "Listener1 got: "; iValue
END METHOD
END INTERFACE
END CLASS
CLASS Listener2 AS EVENT
INTERFACE IEvents
INHERIT IUNKNOWN
AS EVENT
METHOD MyEvent(BYVAL iValue AS LONG)
PRINT "Listener2 got: "; iValue
END METHOD
END INTERFACE
END CLASS
CLASS EventSource
INTERFACE IEvents ' redeclared inside the source (empty bodies)
INHERIT IUNKNOWN
METHOD MyEvent(BYVAL iValue AS LONG)
END METHOD
END INTERFACE
INTERFACE ISource
INHERIT IUNKNOWN
METHOD Trigger()
RAISEEVENT IEvents.MyEvent(42)
END METHOD
END INTERFACE
EVENT SOURCE IEvents ' this class raises IEvents events
END CLASS
FUNCTION PBMAIN() AS LONG
LOCAL src AS ISource
LOCAL l1 AS IEvents
LOCAL l2 AS IEvents
LET src = CLASS "EventSource"
LET l1 = CLASS "Listener1"
LET l2 = CLASS "Listener2"
EVENTS FROM src CALL l1 ' subscribe the listeners
EVENTS FROM src CALL l2
src.Trigger() ' raises MyEvent(42)
EVENTS END l1 ' unsubscribe
EVENTS END l2
FUNCTION = 0
END FUNCTION
The event interface is declared once at module level. The source class redeclares it nested, adds EVENT SOURCE, and fires events with RAISEEVENT IEvents.Method(args). Listener classes are declared AS EVENT. EVENTS FROM subscribes a listener and EVENTS END unsubscribes it; RAISEEVENT dispatches to all registered listeners via runtime helpers (bestof_events_from, bestof_events_end, bestof_raiseevent_0..6). Full regression test: test_class_events_multi.pb.
WITH - Block-level Member Access
WITH block for shorthand access
#COMPILE EXE
#DIM ALL
TYPE Counter
count AS LONG
label AS STRING
END TYPE
FUNCTION PBMAIN() AS LONG
LOCAL c AS Counter
WITH c
.label = "clicks"
.count = 0
.count = .count + 1
.count = .count + 1
PRINT .label; ": "; .count ' clicks: 2
END WITH
FUNCTION = 0
END FUNCTION
WITH saves the variable reference and expands .field prefixes throughout the block, so the variable name is not repeated. It works on TYPE variables; for interface objects use the object name. The variable is stored in fn->with_var and used by the expression and decl parsers.