OberonCore

Библиотека  Wiki  Форум  BlackBox  Компоненты  Проекты
Текущее время: Четверг, 28 Март, 2024 22:04

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 18 ] 
Автор Сообщение
СообщениеДобавлено: Суббота, 21 Октябрь, 2017 20:02 

Зарегистрирован: Пятница, 13 Март, 2009 16:36
Сообщения: 987
Откуда: Казань
Читаю книгу "Object-oriented programming in Oberon-2" и там есть описание простой оконной системы, которая называется Oberon0 (не путать с простым компилятором Oberon-0, из книги "Compiler construction"). Так вот Frame-ы и Viewer-ы описываются следующим образом:
Код:
TYPE
  Frame* = POINTER TO FrameDesc;
  FrameDesc* = RECORD (OS.ObjectDesc)
    x*, y*: INTEGER; (*left bottom in pixels relative to left bot. of screen*)
    w*, h*: INTEGER (*width, height in pixels*)
  END;
  Viewer* = POINTER TO ViewerDesc;
  ViewerDesc* = RECORD (FrameDesc)
    menu-, cont-: Frame; (*menu frame, contents frame*)
    next-: Viewer;
  END;

То есть Viewer-ы организованы в список и у каждого Viewer-а есть указатель на следующий Viewer или на NIL. (Думаю, что и в BlackBox организация данных примерно такая же.)
А что, если бы модуль мог содержать не Viewer, а ViewerDesc и допустим можно было бы их так же организовывать в списки при необходимости. Тогда не нужно было бы вызывать NEW для создания объекта, а объекты создавались бы при загрузке модуля сразу в глобальной памяти. То есть был бы примерно такой код:
Код:
MODULE MainForm;
  IMPORT ...;

  VAR
    mainForm: ViewerDescr;
    someControl: ViewerControlDescr;
    ...

END MainForm.

Думаю, что в данном случае, были бы следующие преимущества:
1) Загружалось бы все быстрее, за счет того, что не нужно выделять память при помощи NEW.
2) Снижалась бы нагрузка на GC, и в принципе можно было бы создавать графические программы, которые вообще не обращаются к динамической памяти, а работают только с глобальной памятью и стеком программы.

Какие у данного метода могут быть недостатки?
Может быть данный метод уже где-то был реализован?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Суббота, 21 Октябрь, 2017 22:34 

Зарегистрирован: Четверг, 08 Май, 2008 19:13
Сообщения: 1447
Откуда: Киев
Сколько Viewer-ов присутствует в типичной системе и насколько это большая нагрузка на динамическую память?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 22 Октябрь, 2017 07:50 

Зарегистрирован: Вторник, 26 Январь, 2010 09:31
Сообщения: 717
Откуда: Барнаул
а как из них список сделать?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 22 Октябрь, 2017 09:15 

Зарегистрирован: Понедельник, 28 Ноябрь, 2005 10:28
Сообщения: 1428
в статической памяти логичнее было бы массив.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 22 Октябрь, 2017 10:26 

Зарегистрирован: Вторник, 26 Январь, 2010 09:31
Сообщения: 717
Откуда: Барнаул
с вполне конкретным именем, чтобы можно было стандартно дергать


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 22 Октябрь, 2017 10:29 

Зарегистрирован: Воскресенье, 28 Май, 2006 22:12
Сообщения: 1693
Rifat писал(а):
Читаю книгу "Object-oriented programming in Oberon-2" и там есть описание простой оконной системы, которая называется Oberon0 (не путать с простым компилятором Oberon-0, из книги "Compiler construction"). Так вот Frame-ы и Viewer-ы описываются следующим образом
...
А что, если ...
...
Какие у данного метода могут быть недостатки?
Может быть данный метод уже где-то был реализован?

Рифат, Ваш вопрос - несколько шире, чем конкретная реализация View.

В данном случае (как и во многих других), Вирт сделал методологическую и архитектурную ошибку, внеся знания о возможных отношениях, в которых может быть задействована и/или участвовать данная сущность в саму сущность.
Если таких отношений может быть всего одно ( как в случае со списком views ), - это кажется несущественным.
Но, исходя из общих подходов, лучше сделать общий класс List, оперирующий с элементами ЛЮБЫХ ссылочных/указательных типов.

Тогда бы и вопроса о том, каков способ создания и место нахождения экземпляра не имел бы значения.

Как только мы приходим к такому решению на уровне системы, моментально возникает задача (де)инициализации.
Эта задача также переходит на уровень общесистемной.
То есть, экземпляр может быть в куче или где-то статически. Инициализировать (экземпляр) нужно в любом случае.
Возникает инициализирующая часть. OurType_Init( OurTypePtr self, ...args...).
И - для размещения в куче, что-то "фабричное" - OurType OurType_Create( ...args... ), которое может вызывать ( может и - нет ) ***_Init.
Соответственно, можно организовать ***_DeInit & ****_Free (последний - для тэггированных типов).

Было принято неверное упрощённое решение, исходя из посыла простоты частного случая. Плюс отсутствие параметризации в языке.
Если есть желание, могу привести пример таких списков (но - на Си), которые я применяю в своих системах. Переделать подход для Оберона не составит труда, я думаю.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 22 Октябрь, 2017 10:54 

Зарегистрирован: Воскресенье, 28 Май, 2006 22:12
Сообщения: 1693
Добавлю.

Конечно, сборка мусора упрощает проектирования.
Но, она же, вносит и огромный пласт безответственности и невнимательности при проектировании.
В частности, люди совершенно упускают из виду:
- различия между местами хранения сущностей (статика/куча)
- роль конкретного списка (владелец элементов или "обозначатель" принадлежности сущности ко множеству/объединение сущностей с имеющимся признаком)
- необходимость уделять внимание дополнительным операциям при удалении элемента из данного списка

Методологически полезней изначально проектировать системы так, как будто сборки мусора нет. То есть, решать более общую задачу. Потом, части системы, отвечающие за очистку и удаление элементов - просто комментируются или удаляются из исходников.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 22 Октябрь, 2017 12:29 
Аватара пользователя

Зарегистрирован: Пятница, 25 Ноябрь, 2005 12:02
Сообщения: 8500
Откуда: Троицк, Москва
Сборка мусора позволяет разделить (#2 DIVIDE ET IMPERA) разработку алгоритмов и оптимизацию в весьма чреватом аспекте управления памятью.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 23 Октябрь, 2017 01:58 

Зарегистрирован: Воскресенье, 28 Май, 2006 22:12
Сообщения: 1693
Info21 писал(а):
Сборка мусора позволяет разделить (#2 DIVIDE ET IMPERA) разработку алгоритмов и оптимизацию в весьма чреватом аспекте управления памятью.

Разделить - нет.
Получить иллюзию - да.
Не всё так просто, как хотелось изначально.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 23 Октябрь, 2017 10:15 

Зарегистрирован: Пятница, 13 Март, 2009 16:36
Сообщения: 987
Откуда: Казань
В одной из старых тем было высказывание Федора Васильевича (и еще когда-то Илья Ермаков тоже высказывал похожую мысль):
Info21 писал(а):
Сформулирую главную мысль покороче, повторившись в 100000-й раз:

В отличие от всевозможных интерпретируемых языков (ФЯ и проч.)
автоматическое управление памятью в Обероне позволяет разделить (DIVIDE ET IMPERA) две важные и разные вещи:

фазу проектирования структур данных -- когда нужные структуры данных еще не известны -- и

фазу их оптимизации -- когда структуры данных в случае нужды (sic) отображаются на статическую память.

Получается, что в случае нужды с View, их не так то просто отобразить в статическую память. Как писал Wlad нужна инициализация, освобождение и так далее. Но в принципе, конечно, ничего невозможно нет. Можно и существующими средствами достичь того, что View будут хранится в статической памяти.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 23 Октябрь, 2017 10:18 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9459
Откуда: Россия, Орёл
Нужна конкретная постановка задачи.

Вам нужно использовать Viewer-ы в системе реального времени?

Подход Дагаева - выделили на старте нужное количество (или в пул с запасом) - и дальше используете, с уже выключенным NEW/GC.

Можно поиграть, если есть необходимость, и с другой стратегией выделения таких объектов - тупо линейной (как выделяются объекты в первом поколении в .NET), когда нарезается следующий кусок нужного размера под объект в линейной области памяти.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 23 Октябрь, 2017 11:38 

Зарегистрирован: Пятница, 13 Март, 2009 16:36
Сообщения: 987
Откуда: Казань
На самом деле нет никакой постановки задачи. Есть только когнитивный диссонанс :)
У меня всегда было представление, что когда точно известно сколько будет элементов, то лучше завести массив или список в статической памяти и уже с ним работать.
Динамическую память следует использовать тогда, когда точно не известно сколько будет элементов.
При проектировании GUI, чаще всего бывает известно, сколько контролов будет на форме и где они будут располагаться. То есть по идее, лучше бы их разместить статически, а не динамически.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 23 Октябрь, 2017 16:11 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9459
Откуда: Россия, Орёл
Угу, а потом получается, что если рассматривать существующие библиотеки GUI-виджетов как вариант для порта ББ, то часть из них пролетает в силу того, что у них состав элементов задаётся статически.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 23 Октябрь, 2017 16:41 

Зарегистрирован: Пятница, 13 Март, 2009 16:36
Сообщения: 987
Откуда: Казань
В принципе, конечно, можно реализовать вариант и со статическим размещением объектов в Обероне, но это будет выглядеть как "закат Солнца вручную".
Другое дело, перевешивают ли плюсы такого подхода минусы "заката Солнца вручную"?
То, есть что можно выиграть за счет того, что все будет размещаться статически?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 23 Октябрь, 2017 17:19 

Зарегистрирован: Воскресенье, 28 Май, 2006 22:12
Сообщения: 1693
Rifat писал(а):
На самом деле нет никакой постановки задачи. Есть только когнитивный диссонанс :)
У меня всегда было представление, что когда точно известно сколько будет элементов, то лучше завести массив или список в статической памяти и уже с ним работать.
Динамическую память следует использовать тогда, когда точно не известно сколько будет элементов.
При проектировании GUI, чаще всего бывает известно, сколько контролов будет на форме и где они будут располагаться. То есть по идее, лучше бы их разместить статически, а не динамически.

Кстати, я использую "динамику" и в РВ системах. Но - как...
Например, для обобщённых списков.
Иногда я не знаю, сколько действительно элементов (например, "растянутая" по времени обрабатываемая команда) мне понадобится. Но я знаю, что элементы данного типа постоянно появляются и исчезают. Ввожу кэш/пул объектов в каждый такой тип. Дальше функция new/create "лезет" не к менеджеру памяти, а, сначала, в этот пул. Соответственно, освобождения памяти не происходит, а объект возвращается в пул объектов данного типа.
При старте программы, можно просто заранее заполнить пулы определённым количеством неинициализированных объектов.
Кстати и "сборка мусора" происходит путём "прочёсывания" списка всех пулов в системе. С конца списка. Потому, что в начало списка помещаются пулы, к которым происходит наиболее частое обращение.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 23 Октябрь, 2017 17:38 

Зарегистрирован: Воскресенье, 28 Май, 2006 22:12
Сообщения: 1693
Ещё пар мыслей...
Кстати, работа со списками намного облегчается, если в списке хранятся не сами экземпляры объектов, а некие ссылочные элементы на объекты. Такое разделение позволяет легко реализовать дисциплину разделения "типов" хранимых объектов по месту создания/нахождения - в динамической и статической памяти. При внесении элемента в список, одним из аргументов можно передавать указатель на функцию-"деструктор" хранимого объекта. Тогда упрощается и операция копирования списка. Копируется/создаются "ссылки" вместе с самими объектами. Следовательно копируются и указатели на "деструкторы"/"деинициализаторы" соответствующих объектов.
Автоматом получается более правильное и чистое решение на счёт разделения "базового" функционала объектов и информации о том, в какие множества (списки) этот объект входит. Кроме того, мы автоматом получаем реализацию свойства "владения" списком своих элементов. Нет указателя на "деструктор" - нет и "владения" - элемент уничтожается где-то кем-то другим.

Ниже - заголовочный файл более "лёгкого" решения (ещё без внесения того, что описано выше в "ссылку"-элемент списка). Здесь дисциплина "владения" и освобождения объекта, при удалении списка или объекта из него "отдано на откуп" функциям, связанным с этими операциями.
Атрибут ICACHE_FLASH_ATTR означает размещение кода функции во флэш-памяти контроллера.
Код:
#ifndef __LISTS_H__
#define __LISTS_H__
//----------------------------------------------------------------------------
#include "lists_cfg.h"
#include "macros.h"
#include "typedefs.h"

typedef enum
{ List_Insert_Positions_Before
, List_Insert_Positions_After
} List_Insert_Positions_e;

typedef enum
{ LIST_ENTRY_MOVE_FIRST = (-2)
, LIST_ENTRY_MOVE_PREV  = (-1)
, LIST_ENTRY_MOVE_STAY  = 0
, LIST_ENTRY_MOVE_NEXT  = 1
, LIST_ENTRY_MOVE_LAST  = 2
} List_Entry_Move_Directions_e;

//----------------------------------------------------------------------------
struct _List_Entry;
#define List_Entry  struct _List_Entry*

struct _List;
#define List  struct _List*

typedef struct _List_Entry
{
   List        _list;
   List_Entry  _prev;
   List_Entry  _next;
   void* const _object;
} List_Entry_t;

//----------------------------------------------------------------------------
typedef struct _List
{
   List_Entry _first;
   List_Entry _last;
   int        _count;
} List_t;

//----------------------------------------------------------------------------
typedef void (*List_ObjectFunc     )(       List_Entry entry  ,       void* arg     );
typedef bool (*List_CheckObjectFunc)( const void*      object , const void* arg     );
typedef bool (*List_CmpObjectsFunc )( const void*      object1, const void* object2 ); //(*CmpFun)(object1,object2) must return TRUE if object1 "<=" object2
typedef void (*List_FreeObjectFunc )(       void*      object                       );

//----------------------------------------------------------------------------
List       ICACHE_FLASH_ATTR List_Create      ( void );
bool       ICACHE_FLASH_ATTR List_Init        (       List list );
bool       ICACHE_FLASH_ATTR List_DeInit      (       List list, List_FreeObjectFunc FreeObjectFunc );
bool       ICACHE_FLASH_ATTR List_Free        (       List list, List_FreeObjectFunc FreeObjectFunc );

// List_Clear just removes items all from the list (if FreeItemFunc == NULL) or frees them (if FreeItemFunc != NULL)
bool       ICACHE_FLASH_ATTR List_Clear       (       List list, List_FreeObjectFunc FreeObjectFunc );
bool       ICACHE_FLASH_ATTR List_IsEmpty     ( const List list );

List_Entry ICACHE_FLASH_ATTR List_Add         (       List list, const void* const object );
List_Entry ICACHE_FLASH_ATTR List_Insert      (       List list, const void* const object, List_Entry entry, List_Insert_Positions_e pos );
bool       ICACHE_FLASH_ATTR List_Remove      (       List list, List_Entry entry, List_FreeObjectFunc FreeObjectFunc );

bool       ICACHE_FLASH_ATTR List_Move        (       List list, List_Entry entry, List_Entry_Move_Directions_e direction );

List_Entry ICACHE_FLASH_ATTR List_First       ( const List list );
List_Entry ICACHE_FLASH_ATTR List_Prev        ( const List list, List_Entry entry );
List_Entry ICACHE_FLASH_ATTR List_Next        ( const List list, List_Entry entry );
List_Entry ICACHE_FLASH_ATTR List_Last        ( const List list );


void       ICACHE_FLASH_ATTR List_ForEach     ( const List list, List_ObjectFunc ObjectFunc, void* itemFuncArg );
//(*CmpFun)(object1,object2) must return TRUE if object1 "<=" object2
bool       ICACHE_FLASH_ATTR List_Sort        (       List list, List_CmpObjectsFunc CmpFunc );

List_Entry ICACHE_FLASH_ATTR List_Find        ( const List list, List_CheckObjectFunc CheckFunc, const void* checkFuncArg );
List_Entry ICACHE_FLASH_ATTR List_FindByObject( const List list, const void* object );

bool       ICACHE_FLASH_ATTR List_Assign      (       List list, const List src );

//----------------------------------------------------------------------------
   bool ICACHE_FLASH_ATTR Lists_Init( void );

#endif // #ifndef __LISTS_H__


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 23 Октябрь, 2017 18:03 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9459
Откуда: Россия, Орёл
Предлагаю автору перемещение ветки в Системные вопросы.
Однозначно по тематике туда.

Если Rifat не против, то попросим модераторов перекинуть.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 23 Октябрь, 2017 21:36 

Зарегистрирован: Пятница, 13 Март, 2009 16:36
Сообщения: 987
Откуда: Казань
Я не против)


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 18 ] 

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Вся информация, размещаемая участниками на конференции (тексты сообщений, вложения и пр.) © 2005-2024, участники конференции «OberonCore», если специально не оговорено иное.
Администрация не несет ответственности за мнения, стиль и достоверность высказываний участников, равно как и за безопасность материалов, предоставляемых участниками во вложениях.
Без разрешения участников и ссылки на конференцию «OberonCore» любое воспроизведение и/или копирование высказываний полностью и/или по частям запрещено.
Powered by phpBB® Forum Software © phpBB Group
Русская поддержка phpBB