Constructor Called - But not Working

I have a problem when I drop a class on my window (which I would like because I have event definitions) which is really annoying. What I do:
-Create a class and set one or two values in the constructor
-Drag it to window1.
-Calling a method of this class and display the value(s).

First the values are shown correctly. Then I program a little bit more and suddenly the values aren’t set anymore (but constructor is called!). To solve this I just delete the class on my window1 and drag the class again into the window1 and my problem is solved.

I’ve uploaded a example project:
http://www.speedyshare.com/vPKDQ/class-problem.xojo-binary-project

if you open project in Arbed, you can see the control instance here.
And there your values are stored.
So xojo calls constructor, you set values and than Xojo loads into object the initial values defined in control instance on window.

[quote=119311:@Urs Jäggi]I have a problem when I drop a class on my window (which I would like because I have event definitions) which is really annoying. What I do:
-Create a class and set one or two values in the constructor
-Drag it to window1.
-Calling a method of this class and display the value(s).

First the values are shown correctly. Then I program a little bit more and suddenly the values aren’t set anymore (but constructor is called!). To solve this I just delete the class on my window1 and drag the class again into the window1 and my problem is solved.

I’ve uploaded a example project:
http://www.speedyshare.com/vPKDQ/class-problem.xojo-binary-project[/quote]

Nothing wrong here. Values are correctly set and retrieved. I added a new property in the class and it is available fine in the window instance.

Mac OS X 2014 R2.1.

You have entered initial values for the two variables in three locations:

  • in the MyClass “Property List” (right click on MyClass and choose the “Inspector Behavior…” menu item)
  • in the property definition text field in the inspector
  • in the Constructor

Choose one of them and you’re good to go.

Xojo behaves weirdly with the preallocated values. It’s something like this:

People expect, as other environments, is does initializations like the following:

[code]Class._init() //<-- allocate things, set initial values, etc. Raise Constructor(), open()…
Event Class.Constructor()
Event Class.Open()
//-- Object life
Event Class.Close()
Event Class.Destructor()
Class._release() // Internal clean up

And Xojo does anything like this (I do consider it an irritating bug, some say it’s a “characteristic”):

Class._init() //<-- allocate things, etc. Raise Constructor(), open(), _init_values()… !!! Wow!!! What?
Event Class.Constructor()
Event Class.Open()
Event _init_values() // !!! What? this hidden “event” destroyed my settings in the constructor?
// Have I made wrong calculations in the open() without my predefined values?
//-- Object life
Event Class.Close()
Event Class.Destructor()
Class._release() // Internal clean up

Expected Behavior:

Class MyClass

  Property Public n1 As integer = 123
  Property Public n2 As integer = 0

  Sub Constructor()
     n2 = n1 * 2
  End Sub

End Class

Dim c As New MyClass // c.n2 = 246

What Xojo does (something like):

Class MyClass

  //Property Public n1 As integer = 123
  //Property Public n2 As integer = 0

  Property Public n1 As integer = 0
  Property Public n2 As integer = 0

  Sub Constructor()
     n2 = n1 * 2  // ------ 0 * 2 = 0
  End Sub

  Sub _init_values()  // Called after Constructor, after Open() it it have one, not sure,
                     // don't remember the fail exactly
     n1 = 123
  End Sub
End Class

Dim c As New MyClass // c.n2 = 0, and n1 was 0 too at constructor() time.

This is only somehow true for windows, controls and class instances added to a window via the IDE. It doesn’t happen with class instances created in code.

But then why would somebody want to set the initial value twice - or even three times as in the OP - on an class instance added to a window via the IDE? Just set it in the IDE, or use the window’s Open event (which is guaranteed to be the last on window startup).

[quote=119403:@Rick Araujo]Expected Behavior:

Class MyClass

Property Public n1 As integer = 123
Property Public n2 As integer = 0

Sub Constructor()
n2 = n1 * 2
End Sub

End Class
Dim c As New MyClass // c.n2 = 246[/quote]
Works perfectly. Both when the class is added and instantiated in code in a window or dragged onto the window in the navigator.

No one. Just want to use the correct values set once, and can’t.

But when you put a value in the “Default” text field of the property definition, why would you want to set the initial value again int he constructor?

What about use the value? Maybe talking this way the concept can be better understandable. I’ll define a property called PI and set it’s value to 3.14 in the constructor If I use it I wish to use it as 3.14, not zero? Is it hard to understand?

In any other language of this world preinitialized values comes with it’s values predefined. Interestingly even Xojo! Sometimes…

The problem is this “Sometimes”. Should be Ever! The name of this is consistence of behavior.

It is consistent if you think about how Xojo works!

When you drag a class (or control) onto a window an instance of that class is created. If you later change something in the class, which is not compilable source code, it will not be reflected in this specific instance.

Putting a value into the “Default” text field of a property definition is read only once by the IDE (when dragging the class onto the window thereby creating the instance), not on compile time.

I don’t get it. How can I change a class without changing a class? You mean class or runtime instance?

For example if you later change the “Default” value in the text field of a property definition. This change will not be reflected in all existing instances, only on instances which one creates later.

This kind of behavior can introduce bugs if you forget to change those old values to the new ones, but it’s really not the heart of the question here. The real problem is where in time those values are set. They must be pre-constructor. Init time. Not post-constructor. We must receive the preset values in the user space since t0. We can’t start use the preset values and a exotic xojo intrusion comes from nowhere and change the property values.

When you write your “default” value in Xojo, they are written as:

Dim p As Type = Value

Not:

Dim p As Type = Nil SetEvent_SetValueAfterOpen(self, p, Value)

Again: a default value entered in the IDE in the property definition text field
Dim p As Type = Value
… is applied at creation of the instance - when the class (or control) is dragged onto the window.

You should see a window instance in the IDE as a live object (like XIBs in Xcode), not as a piece of source code (like in Visual Studio). Then it makes perfect sense.

A live object is an instance, which can, and is, converted to source code (Like Delphi does). It have native support in the language for that. For example, here is a Sub-class of a Form (Window) with all the designs and components and it’s initial values.

type
  TForm1 = class(TForm)      //<— Define the class, the implementation of the procedure will be elsewhere after.
                                 // Not included here.
    db1: TSL_Database;
    table1: TSL_Table;
    OpenDialog1: TOpenDialog;
    Panel1: TPanel;
    tvBrowse: TTreeView;
    Panel2: TPanel;
    Splitter1: TSplitter;
    Panel3: TPanel;
    sg1: TBestStringGrid;
    Panel4: TPanel;
    sql2: TSL_Table;
    table2: TSL_Table;
    Panel5: TPanel;
    Panel6: TPanel;
    edSQL: TComboBox;
    MemoTime: TMemo;
    Splitter2: TSplitter;
    bnOpenDB: TButton;
    bnEditTable: TButton;
    bnExecSQL: TButton;
    MainMenu1: TMainMenu;
    Database1: TMenuItem;
    able1: TMenuItem;
    Info1: TMenuItem;
    Libraryversion1: TMenuItem;
    Libraryencoding1: TMenuItem;
    Open1: TMenuItem;
    Edit1: TMenuItem;
    Close1: TMenuItem;
    procedure table1Data(Sender: TObject);
    procedure bnExecSQLClick(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure sql2Data(Sender: TObject);
    procedure bnOpenDBClick(Sender: TObject);
    procedure tvBrowseChange(Sender: TObject; Node: TTreeNode);
    procedure editSelectedTable(Sender: TObject);
    procedure Panel6Resize(Sender: TObject);
    procedure Libraryversion1Click(Sender: TObject);
    procedure Libraryencoding1Click(Sender: TObject);
    procedure Close1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    tableNode : TTreeNode;
    viewNode  : TTreeNode;
    indexNode : TTreeNode;
    dbNode    : TTreeNode;

    procedure processRow(row:TSL_Row;r:integer);
    procedure drawCaptions(row:TSL_Row);
  end;

var
  Form1: TForm1;                // <— Here is the variable. The reference holder of this class.

//======

object Form1: TForm1            // <— Here is the instance declaration. The preset initial values.
                                     // This instance exists since t0 with those numbers.
  Left = 237				// It includes ALL the values, including of sub-compoments of this class
  Top = 242
  AutoScroll = False
  Caption = 'SQLite Browser'
  ClientHeight = 638
  ClientWidth = 898
  Color = clBtnFace
  Font.Charset = ANSI_CHARSET
  Font.Color = clWindowText
  Font.Height = -12
  Font.Name = 'Arial'
  Font.Style = []
  Menu = MainMenu1
  OldCreateOrder = False
  OnShow = FormShow
  PixelsPerInch = 96
  TextHeight = 15
  object Splitter1: TSplitter
    Left = 249
    Top = 0
    Height = 638
  end
  object Panel1: TPanel
    Left = 0
    Top = 0
    Width = 249
    Height = 638
    Align = alLeft
    Caption = 'Panel1'
    TabOrder = 0
    object tvBrowse: TTreeView
      Left = 1
      Top = 34
      Width = 247
      Height = 603
      Align = alClient
      Indent = 19
      TabOrder = 0
      OnChange = tvBrowseChange
      OnDblClick = editSelectedTable
    end
    object Panel2: TPanel
      Left = 1
      Top = 1
      Width = 247
      Height = 33
      Align = alTop
      TabOrder = 1
      object bnOpenDB: TButton
        Left = 4
        Top = 5
        Width = 75
        Height = 25
        Caption = 'Open DB'
        TabOrder = 0
        OnClick = bnOpenDBClick
      end
      object bnEditTable: TButton
        Left = 82
        Top = 5
        Width = 75
        Height = 25
        Caption = 'Edit Table'
        TabOrder = 1
        OnClick = editSelectedTable
      end
    end
  end
  object Panel3: TPanel
    Left = 252
    Top = 0
    Width = 646
    Height = 638
    Align = alClient
    Caption = 'Panel3'
    TabOrder = 1
    object Splitter2: TSplitter
      Left = 1
      Top = 545
      Width = 644
      Height = 3
      Cursor = crVSplit
      Align = alBottom
    end
    object sg1: TBestStringGrid
      Left = 1
      Top = 35
      Width = 644
      Height = 510
      Align = alClient
      ColCount = 2
      DefaultRowHeight = 18
      DefaultDrawing = False
      Font.Charset = ANSI_CHARSET
      Font.Color = clWindowText
      Font.Height = -12
      Font.Name = 'Arial'
      Font.Style = []
      Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goColSizing, goThumbTracking]
      ParentFont = False
      TabOrder = 0
      OrderIcon = False
      OwnerDrawText = False
      ColWidths = (
        12
        64)
    end
    object Panel4: TPanel
      Left = 1
      Top = 1
      Width = 644
      Height = 34
      Align = alTop
      TabOrder = 1
      object Panel5: TPanel
        Left = 530
        Top = 1
        Width = 113
        Height = 32
        Align = alRight
        BevelOuter = bvNone
        TabOrder = 0
        object bnExecSQL: TButton
          Left = 16
          Top = 3
          Width = 94
          Height = 26
          Caption = 'Exec SQL'
          TabOrder = 0
          OnClick = bnExecSQLClick
        end
      end
      object Panel6: TPanel
        Left = 1
        Top = 1
        Width = 529
        Height = 32
        Align = alClient
        BevelOuter = bvNone
        TabOrder = 1
        OnResize = Panel6Resize
        object edSQL: TComboBox
          Left = 5
          Top = 5
          Width = 431
          Height = 23
          ItemHeight = 15
          TabOrder = 0
          Text = 'select * from sqlite_master;'
        end
      end
    end
    object MemoTime: TMemo
      Left = 1
      Top = 548
      Width = 644
      Height = 89
      Align = alBottom
      TabOrder = 2
    end
  end
  object db1: TSL_Database
    Left = 40
    Top = 320
  end
  object table1: TSL_Table
    Database = db1
    SQL = 'select _ROWID_,* from songs limit 1000;'
    OnData = table1Data
    Left = 40
    Top = 376
  end
  object OpenDialog1: TOpenDialog
    Left = 48
    Top = 136
  end
  object sql2: TSL_Table
    Database = db1
    SQL = 'select ROWID,* from sqlite_master;'
    OnData = sql2Data
    Left = 40
    Top = 432
  end
  object table2: TSL_Table
    Database = db1
    Left = 40
    Top = 264
  end
  object MainMenu1: TMainMenu
    Left = 396
    Top = 56
    object Database1: TMenuItem
      Caption = 'File'
      object Open1: TMenuItem
        Caption = 'Open Database'
        OnClick = bnOpenDBClick
      end
      object Close1: TMenuItem
        Caption = 'Close'
        OnClick = Close1Click
      end
    end
    object able1: TMenuItem
      Caption = 'Table'
      object Edit1: TMenuItem
        Caption = 'Edit'
        OnClick = editSelectedTable
      end
    end
    object Info1: TMenuItem
      Caption = 'Info'
      object Libraryversion1: TMenuItem
        Caption = 'Library version'
        OnClick = Libraryversion1Click
      end
      object Libraryencoding1: TMenuItem
        Caption = 'Library encoding'
        OnClick = Libraryencoding1Click
      end
    end
  end
end

You’re obviously not getting it.

I got. It’s wrong. I believe you can’t see how wrong it is. And how it’s fixed by something like I demonstrated above.

I wrote a long post on the forums about exactly this issue
It’s existed for many many years

And it figures I can’t find the thread