LINUX.ORG.RU

[cl] как лучше сделать геттеры/сеттеры для структуры


0

0

У меня есть такая структура:

(defstruct file
  (name "")
  (path "")
  (allow-groups nil)
  (allow-users nil)
  (deny-users nil))

Для каждого поля, кроме name, нужно прописать геттер и сеттер. Как лучше всего сделать их, если число параметров в дальнейшем может увеличиться?

У меня есть два варианта:

1. Для каждого прописывать что-то типа get-file-allow-groups и set-file-allow-groups, в результате получится 8 функций. При увеличении числа полей структуры прописывание для каждого геттера/сеттера может стать мозгоебством большой проблемой.

2. Одна мега-функция, принимающая параметр типа :allow-groups или :deny-users, который указывает поле для работы. Но мне кажется, это будет просто одна _большая_ функция вместо нескольких маленьких, как в 1 случае.

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

★★

Накрути что-то, аналогичное property в питоне - когда читая поле ты получаешь геттер, а присваивая полю что-либо - вызываешь сеттер.

Я не в курсе как такое делать на cl, но уверен что можно.

anonymous
()
Ответ на: комментарий от anonymous

Макрос defstruct такое делает сам. Мне нужно сделать обертку над каждым геттером и сеттером структуры (для некоторых проверок и т.п.).

Наверное, придется писать набор функций, другого варианта я не вижу.

bk_ ★★
() автор топика
Ответ на: комментарий от bk_

> Наверное, придется писать набор функций, другого варианта я не вижу.

ну когда реализуешь считывателей мыслей, который будет из твоего мозга читать какая функция тебе нужна и самостоятельно описывать ее на выбраном ЯП, тогда и будешь задавать вопрос «А как лучше сделать...?»

korvin_ ★★★★★
()

вообще, кстати говоря, автор PCL утверждает, что такие макры (которые генерят символы и биндят их в топлевеле) — зло, поэтому лучше юзать не структуры defstruct, а классы defclass (думаю, учитывая, что структуры в CL весьма «жирные», можно вполне заюзать и классы)

korvin_ ★★★★★
()
Ответ на: комментарий от bk_

> Сер, да вы прямо эксперт.

нет, я только учусь

korvin_ ★★★★★
()
Ответ на: комментарий от korvin_

> (думаю, учитывая, что структуры в CL весьма «жирные», можно вполне заюзать и классы)

ну а при желании можно реализовать свои лёгкие, нежирные метаклассы

korvin_ ★★★★★
()
Ответ на: комментарий от korvin_

Я просто не хотел проблем с сохранением/загрузкой из файла. Структуру можно сохранить простым print'ом, а класс надо по своему распарсивать.

В моем проекте скорее важна скорость написания, а не красота.

bk_ ★★
() автор топика
Ответ на: комментарий от bk_

Структуру можно сохранить простым print'ом, а класс надо по своему распарсивать.

что?

Вы имеете в виду вывод #S(...) ? это не сохранение структуры, а сохранение её данных, такое легко написать для любого класса:

(defclass foo ()
  ((name :initarg :name :accessor foo-name)))

(defmethod print-object ((x foo) stream)
  (format stream "(new 'foo :name ~s)" (foo-name x)))

(defun new (class &rest init-args) ; Чисто new короче, чем make-instance
  (apply #'make-instance class init-args))

CL-USER> (foo-name x)
"Vasya"

(setq y
      (eval ;; эмуляция компиляции
       (read-from-string "(new 'foo :name \"Vasya\")"))) ;; из исходника
(new 'foo :name "Vasya")

CL-USER> (foo-name y)
"Vasya"

CL-USER> (string= (foo-name x) (foo-name y))
T

CL-USER> 
korvin_ ★★★★★
()
Ответ на: комментарий от bk_

> Я просто не хотел проблем с сохранением/загрузкой из файла.

А какие там проблемы? МОжно же тупо писать s-expressions прямо в файл, а потом его загрузить прямо в программе с помощью load.

В моем проекте скорее важна скорость написания, а не красота.

Для проверок уже существующих функций лучше использовать CLOS, там как раз для этого все есть, и очень быстро и красиво записывается. Пока совершенно непонятно, какую ты решаешь проблему, но судя по всему не ту, которую нужно.

anonymous
()
Ответ на: комментарий от korvin_

структуры в CL как раз таки очень легковесны
они хранят минимум метаинформации, например, протокол их создания предельно упрощен и т.п., поэтому занимают мало памяти, быстро создаются, и доступ к их слотам тоже довольно быстр.
они, собственно, поэтому и оставлены в стандарте, даже после того, как появилась CLOS

Love5an
()
Ответ на: комментарий от Love5an

На самом деле я невнятно написал.

У меня есть список структур. Это определено в пакете, а наружу выставлены функции типа

(add-allow-group file-name new-allow-group)
, и так для каждого типа (allow-group, allow-users, deny-users). Причем есть 4 типа операций: add, remove, get, set.

В результате для 3 полей структуры нужно по 4 функции = 12 функций надо прописывать вручную. Хотя, я только что прикинул, что можно сделать 4 унифицированные функции, которые работают с абстрактным списком, и им уже передавать сам рабочий список и параметры.

bk_ ★★
() автор топика
Ответ на: комментарий от anonymous

Тупо как раз не получается.

bk_ ★★
() автор топика
Ответ на: комментарий от korvin_

defclass тоже генерит такие же штуки как и defstruct :) Первые лучше использовать при наследовании (хотя у структур есть конструкторы с копированием) и при сложных реализациях различных ООП вещей (диспетчеризация), вроде методов :around, :before. Ну а так, чтобы обвернуть несколько значений - почему бы не использовать структуру?

anonymous
()
Ответ на: комментарий от anonymous

defclass тоже генерит такие же штуки как и defstruct

генерят символы и биндят их в топлевеле

CL-USER> (defclass foo ()
           ((slot :initform nil :initarg :slot)))
#<STANDARD-CLASS FOO>
CL-USER> (fboundp 'foo-slot)
NIL
CL-USER> (boundp 'foo-slot)
NIL
CL-USER> (defstruct bar slot)
BAR
CL-USER> (fboundp 'bar-slot)
T
CL-USER> 

так понятней, что я имел в виду? а что имели в виду Вы?

korvin_ ★★★★★
()
Ответ на: комментарий от korvin_

[b]Корвин[/b], да нет, всё прекрасно создаётся - вы указываете имя аккессора и создаётся функция с таким именем, указываете ридер, получаете себе функцию ридер:

[code=lisp] * (defclass moo () ((boo :initarg :boo :accessor moo-boo :initform 0)))

#<STANDARD-CLASS MOO> * (fboundp 'moo-boo)

T * [/code]

То есть я хотел сказать, что неважно что мы используем структуру или функцию - в общем случае в [s]полку[/s]глобальном пространстве имён прибудет... Хотя да - в классах способ введения таких функций более гибкий.

anonymous
()
Ответ на: комментарий от anonymous

Э,., чё за фигня... Ну вы поняли вобщем :)

anonymous
()
Ответ на: комментарий от dmitry_vk

Это понятно, нужно же как-то ещё убеждать себя что разделение объектов на структуры и классы это не издержки стандарта или эффективности сущ. реализаций а что-то осмысленное.

anonymous
()
Ответ на: комментарий от anonymous

А это разделение вполне реальное. Для структур есть более простые ограничения на использование, чем для классов, вследствие чего компиляторам попроще. Например, переопределение структур является undefined behavior, т.е. переносимые лисп-программы не могут переопределять структуры («The consequences of redefining a defstruct structure are undefined.»). В частности, это позволяется адресовать поля структуры напрямую (т.е., по указателю + смещение поля) без всяких метаобъектных хитростей. А для классов и MOP'а (в которых даже простой вызов slot-value может вылиться в интересные вещи, если компилятор недостаточно умен) путь достижения такой оптимизации будет подлиннее и посложнее.

dmitry_vk ★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.