Philosophical question about memory:

Hello,
Currently I am learning ZIG-Langue, I have a project that I use for that.
I was helped a lot to understand packaging with const xxx struct …
My question :
I made structures which include for each model all its functions which it needs, until there, there is no problem.
But I also included an “arraylist” type data structure,

when I read the documentation, I see that we can do create with Allocator and consequently destroy or free.
https://ziglang.org/learn/overview/#manual-memory-management

I only did “clearandfree” everything works.
But wouldn’t it make more sense to take my data structure out of my general structure and use an init(create)remove(free) function

all this to get to clean all the data in progress during a module exit and return to the general module.

Or maybe do a create of my module for example

pub const pnl = struct {
....
  /// define PANEL
  pub const PANEL = struct {
    name:   [] const u8,
    posx:   usize,
    posy:   usize,
    lines:  usize,
    cols:   usize,
    attribut: dds.ZONATRB,
    frame: frm.FRAME ,

    label: std.ArrayList(lbl.LABEL),

    button: std.ArrayList(btn.BUTTON),

    menu: std.ArrayList(mnu.MENU),

    grid: std.ArrayList(grd.GRID),

    field: std.ArrayList(fld.FIELD),

    linev: std.ArrayList(lnv.LINE),
    lineh: std.ArrayList(lnh.LINE),

    // double buffer screen
    buf:std.ArrayList(TERMINAL_CHAR),

    idxfld: usize,
    key   : kbd ,     // Func task
    keyField : kbd ,  // enter up down
    actif: bool
  };

.... function
}

I hope I’m not too stuffy, basically I’m trying to make good code for memory management and currently I’m not satisfied on this part.

When you say “take my data structure out of my general structure” I’m not sure I follow what you mean? Are you saying “take the ArrayLists out of the PANEL struct”?

externalize the PANEL structure of the pnl structure

but maybe I can do that with the all-encompassing pnl structure and then I can destroy it…

Ah, I see. I would ask the question “does this only every belong to the parent struct?” and even there, I personally would pull it out.

I find this helps in design more generally, because if you ever wanted to pass the PANEL struct as an argument to another function, you’d have to un-nest it from the parent structure. Then we have to ask the philosophical question “why are we separating these two things when it is implied that they are intrinsically linked?”

In terms of memory management, you could make it work either way. I don’t think pulling it out from the parent structure will have that big of an effect if you tailor the logic for either condition. I think what you’re facing here is a more general design problem showing up in a question about memory management.

1 Like

I think what you’re facing here is a more general design problem showing up in a question about memory management.

YES

Can you give us some more details on how you intend to use this structure? Do you ever intend on taking it apart from the parent struct and using it separately? Will other objects also have a PANEL identical to this one? If so, I think it deserves to be separate.

yes a Device has a panel
but the program can have several Device
but in general a module = a Device = a solution = easier maintenance.

In some very particular cases, there may be in 1 module, 2 or 3 complex functions each having their own Device

and the generator matrix, she can shop several panels of them that she will save in a JSON and generate source code

Currently, I am at a turning point, where the choice will determine how I will manage the PANEL structure!!!

and as I am alone at home in retirement behind my screen when I was at the office I could talk and by talking often I found the solution

Yeah, my vote is on remove it from the parent structure and give it its own init/deinit functions. At that level, since you have so many array lists, it makes sense to have some handling conventions unique to that panel object. Also, if you ever decide to decouple it or swap it out, you may have a significantly easier time in that case.

Do you plan on using the same allocator for each array list or are you planning on using different allocations strategies for them? I can’t see how the elements they contain are defined so I’m not sure if that would even help in this case.

I’m asking about the allocation strategy because the more embedded these things are in the parent structure, the more awkward it would be to specialize each array list independently. If they can be independently specialized, a single init function probably doesn’t make sense… at that level, you’re looking at a factory pattern of some sort.

1 Like

a single allocator for the PANEL structure

I’m thinking of doing it like this:

  pub  fn newPanelC(vname: [] const u8,
                  vposx: usize, vposy: usize,
                  vlines: usize,
                  vcols: usize,
                  vcadre : dds.CADRE,
                  vtitle: [] const u8 ) *PANEL {

      var device = dds.allocatorPnl.create(PANEL) catch unreachable ;

      device.name   = vname;
      device.posx   = vposx;
      device.posy   = vposy;
      device.lines  = vlines;
      device.cols   = vcols;
      device.attribut = AtrPanel;
      device.frame = undefined;
      device.label  = std.ArrayList(lbl.LABEL).init(dds.allocatorPnl);
      device.button = std.ArrayList(btn.BUTTON).init(dds.allocatorPnl);
      device.menu   = std.ArrayList(mnu.MENU).init(dds.allocatorPnl);
      device.grid   = std.ArrayList(grd.GRID).init(dds.allocatorPnl);
      device.field  = std.ArrayList(fld.FIELD).init(dds.allocatorPnl);
      device.linev  = std.ArrayList(lnv.LINE).init(dds.allocatorPnl);
      device.lineh  = std.ArrayList(lnh.LINE).init(dds.allocatorPnl);
      device.buf    = std.ArrayList(TERMINAL_CHAR).init(dds.allocatorPnl);
      device.idxfld = 9999;
      device.key    =  kbd.none;
      device.keyField = kbd.none;
      device.actif  = true;


      // INIT doublebuffer
      var i:usize = (device.lines+1) * (device.cols+1);
      var doublebuffer = TERMINAL_CHAR  { .ch =  " ",
                                          .attribut = device.attribut,
                                          .on = false};

      // init matrix
      while (true) {
          if (i == 0) break ;
          device.buf.append(doublebuffer) catch unreachable ;
          i -=1 ;
    }


    // init frame Panel
    device.frame = frm.newFrame(device.name,
                              1 , 1,  // border panel
                              device.lines, device.cols,
                              vcadre, frm.AtrFrame,
                              vtitle, frm.AtrTitle );

    return device;

  }

Ah, so you’re building the device into the allocator using the create function and then returning the pointer to the allocator’s memory pool.

So I see your conundrum. You’re using the same allocator for creating the panel as you are for allocating space for the individual arrays inside the panel itself.

I prefer to use different allocators depending on the structure I’m creating unless I’m going to just use the heap and then c-style allocate everything.

How many PANEL objects will you create during the lifetime of your program?

What is the expected lifetime of a PANEL object? Does it exist throughout the whole program, or are they created and destroyed frequently?

1 Like

a) n Panel object since it is a designer

b)
the lifespan of the panels per module is the moment of a definition
I always come back to the central module to define a new panel or assign objects to this panel each time they are different modules

After I keep this definition either in an array PANEL–> json …

Lots of questions that make me think MERCI

1 Like

I don’t understand the problem completely, but have you considered using a multi array list?


const LineInfo = struct {
    linev: lnv.LINE,
    lineh: lnh.LINE,
};
const Ui = struct {
    label: lbl.LABEL,
    button: btn.BUTTON,
};
pub const pnl = struct {
....
  /// define PANEL
  pub const PANEL = struct {
    name:   [] const u8,
    posx:   usize,
    posy:   usize,
    lines:  usize,
    cols:   usize,
    attribut: dds.ZONATRB,
    frame: frm.FRAME ,

    ui: std.MultiArrayList(Ui),
    line : std.MultiArrayList(LineInfo),

    menu: mnu.MENU,
    grid: grd.GRID,
    field: fld.FIELD,

    // double buffer screen
    buf:std.ArrayList(TERMINAL_CHAR),

    idxfld: usize,
    key   : kbd ,     // Func task
    keyField : kbd ,  // enter up down
    actif: bool
  };

.... function
}

I have the answer,
I just wanted to discuss how to lay out my architecture, and insert a “create” so that I can free the memory.

I have panel that corresponds to a form, so it’s a heap that includes field , label … with a “create” Panel

I took out the grid which is a module in its own right (treat like a panel) and I included a “create” grid

I solved my problem and at the same time clarified the code.

1 Like