Skip to content

Conversation

@daninus14
Copy link
Contributor

This is a correct implementation of effective slot definitions to mito.

Please see the issue #158

By the way, are there any other slots besides those which need to be available at runtime?

I noticed table-column-references is a reader and not an accessor. Should it be set? See that I am not copying it below.

Take a look at the functionality now:

CL-USER> (defclass c1 ()
  ((name
    :col-type (or :null :text)
    :accessor name))
  (:metaclass mito:dao-table-class))
#<MITO.DAO.TABLE:DAO-TABLE-CLASS COMMON-LISP-USER::C1>
CL-USER> (closer-mop:ensure-finalized (find-class 'c1))
#<MITO.DAO.TABLE:DAO-TABLE-CLASS COMMON-LISP-USER::C1>
CL-USER> (inspect *)

The object is a STANDARD-OBJECT of type MITO.DAO.TABLE:DAO-TABLE-CLASS.
0. %TYPE: (CLASS #<MITO.DAO.TABLE:DAO-TABLE-CLASS COMMON-LISP-USER::C1>)
1. SOURCE: #S(SB-C:DEFINITION-SOURCE-LOCATION :NAMESTRING NIL :INDICES 32787)
2. PLIST: NIL
3. NAME: C1
4. CLASS-EQ-SPECIALIZER: #<SB-PCL::CLASS-EQ-SPECIALIZER #<MITO.DAO.TABLE:DAO-TABLE-CLASS COMMON-LISP-USER::C1>>
5. DIRECT-SUPERCLASSES: (#<MITO.DAO.MIXIN:DAO-TABLE-MIXIN MITO.DAO.MIXIN:SERIAL-PK-MIXIN>
                         #<STANDARD-CLASS MITO.DAO.MIXIN:DAO-CLASS>
                         #<MITO.DAO.MIXIN:DAO-TABLE-MIXIN MITO.DAO.MIXIN:RECORD-TIMESTAMPS-MIXIN>)
6. DIRECT-SUBCLASSES: NIL
7. DIRECT-METHODS: (#(#<SB-MOP:STANDARD-READER-METHOD COMMON-LISP-USER::NAME, slot:NAME, (C1) {1003B70073}>
                      #<SB-MOP:STANDARD-WRITER-METHOD (COMMON-LISP:SETF COMMON-LISP-USER::NAME), slot:NAME, (T
                                                                                                             C1) {1003B70383}>
                      0 0))
8. %DOCUMENTATION: NIL
9. SAFE-P: NIL
10. FINALIZED-P: T
11. %CLASS-PRECEDENCE-LIST: (#<MITO.DAO.TABLE:DAO-TABLE-CLASS COMMON-LISP-USER::C1>
                             #<MITO.DAO.MIXIN:DAO-TABLE-MIXIN MITO.DAO.MIXIN:SERIAL-PK-MIXIN>
                             #<STANDARD-CLASS MITO.DAO.MIXIN:DAO-CLASS>
                             #<MITO.DAO.MIXIN:DAO-TABLE-MIXIN MITO.DAO.MIXIN:RECORD-TIMESTAMPS-MIXIN>
                             #<STANDARD-CLASS COMMON-LISP:STANDARD-OBJECT>
                             #<SB-PCL::SLOT-CLASS SB-PCL::SLOT-OBJECT>
                             #<SB-PCL:SYSTEM-CLASS COMMON-LISP:T>)
12. CPL-AVAILABLE-P: T
13. CAN-PRECEDE-LIST: (#<SB-PCL:SYSTEM-CLASS COMMON-LISP:T>
                       #<SB-PCL::SLOT-CLASS SB-PCL::SLOT-OBJECT>
                       #<STANDARD-CLASS COMMON-LISP:STANDARD-OBJECT>
                       #<MITO.DAO.MIXIN:DAO-TABLE-MIXIN MITO.DAO.MIXIN:RECORD-TIMESTAMPS-MIXIN>
                       #<STANDARD-CLASS MITO.DAO.MIXIN:DAO-CLASS>
                       #<MITO.DAO.MIXIN:DAO-TABLE-MIXIN MITO.DAO.MIXIN:SERIAL-PK-MIXIN>)
14. INCOMPATIBLE-SUPERCLASS-LIST: NIL
15. WRAPPER: #<SB-KERNEL:LAYOUT for C1 {50A48783}>
16. PROTOTYPE: NIL
17. DIRECT-SLOTS: (#<MITO.DAO.COLUMN:DAO-TABLE-COLUMN-CLASS COMMON-LISP-USER::NAME>)
18. SLOTS: (#<MITO.CLASS.COLUMN:COLUMN-STANDARD-EFFECTIVE-SLOT-DEFINITIONS MITO.DAO.MIXIN::CREATED-AT>
            #<MITO.CLASS.COLUMN:COLUMN-STANDARD-EFFECTIVE-SLOT-DEFINITIONS MITO.DAO.MIXIN::UPDATED-AT>
            #<MITO.CLASS.COLUMN:COLUMN-STANDARD-EFFECTIVE-SLOT-DEFINITIONS MITO.DAO.MIXIN::SYNCED>
            #<MITO.CLASS.COLUMN:COLUMN-STANDARD-EFFECTIVE-SLOT-DEFINITIONS MITO.DAO.MIXIN::ID>
            #<MITO.CLASS.COLUMN:COLUMN-STANDARD-EFFECTIVE-SLOT-DEFINITIONS COMMON-LISP-USER::NAME>)
19. PRIMARY-KEY: NIL
20. UNIQUE-KEYS: NIL
21. KEYS: NIL
22. TABLE-NAME: NIL
23. PARENT-COLUMN-MAP: #<HASH-TABLE :TEST EQ :COUNT 0 {1003B5E913}>
24. AUTO-PK: (:SERIAL)
25. RECORD-TIMESTAMPS: (T)
> 18 

The object is a proper list of length 5.
0. 0: #<MITO.CLASS.COLUMN:COLUMN-STANDARD-EFFECTIVE-SLOT-DEFINITIONS MITO.DAO.MIXIN::CREATED-AT>
1. 1: #<MITO.CLASS.COLUMN:COLUMN-STANDARD-EFFECTIVE-SLOT-DEFINITIONS MITO.DAO.MIXIN::UPDATED-AT>
2. 2: #<MITO.CLASS.COLUMN:COLUMN-STANDARD-EFFECTIVE-SLOT-DEFINITIONS MITO.DAO.MIXIN::SYNCED>
3. 3: #<MITO.CLASS.COLUMN:COLUMN-STANDARD-EFFECTIVE-SLOT-DEFINITIONS MITO.DAO.MIXIN::ID>
4. 4: #<MITO.CLASS.COLUMN:COLUMN-STANDARD-EFFECTIVE-SLOT-DEFINITIONS COMMON-LISP-USER::NAME>
> 
0

The object is a STANDARD-OBJECT of type MITO.CLASS.COLUMN:COLUMN-STANDARD-EFFECTIVE-SLOT-DEFINITIONS.
0. SOURCE: NIL
1. NAME: MITO.DAO.MIXIN::CREATED-AT
2. INITFORM: NIL
3. INITFUNCTION: NIL
4. INITARGS: (:CREATED-AT)
5. %TYPE: T
6. %DOCUMENTATION: NIL
7. %CLASS: #<MITO.DAO.TABLE:DAO-TABLE-CLASS COMMON-LISP-USER::C1>
8. ACCESSOR-FLAGS: 15
9. INFO: #S(SB-PCL::SLOT-INFO
            :TYPECHECK NIL
            :ALLOCATION :INSTANCE
            :LOCATION 0
            :READER #<FUNCTION (LAMBDA (&REST SB-PCL::ARGS)
                                 :IN
                                 SB-PCL::INITIALIZE-INTERNAL-SLOT-FUNCTIONS) {1003B5747B}>
            :WRITER #<FUNCTION (LAMBDA (&REST SB-PCL::ARGS)
                                 :IN
                                 SB-PCL::INITIALIZE-INTERNAL-SLOT-FUNCTIONS) {1003B574EB}>
            :BOUNDP #<FUNCTION (LAMBDA (&REST SB-PCL::ARGS)
                                 :IN
                                 SB-PCL::INITIALIZE-INTERNAL-SLOT-FUNCTIONS) {1003B5755B}>
            :MAKUNBOUND #<FUNCTION (LAMBDA (&REST SB-PCL::ARGS)
                                     :IN
                                     SB-PCL::INITIALIZE-INTERNAL-SLOT-FUNCTIONS) {1003B575CB}>)
10. ALLOCATION: :INSTANCE
11. ALLOCATION-CLASS: #<MITO.DAO.MIXIN:DAO-TABLE-MIXIN MITO.DAO.MIXIN:RECORD-TIMESTAMPS-MIXIN>
12. LOCATION: 0
13. COL-TYPE: (OR :TIMESTAMPTZ :NULL)
14. REFERENCES: NIL
15. PRIMARY-KEY: NIL
16. GHOST: NIL
> 
u

The object is a proper list of length 5.
0. 0: #<MITO.CLASS.COLUMN:COLUMN-STANDARD-EFFECTIVE-SLOT-DEFINITIONS MITO.DAO.MIXIN::CREATED-AT>
1. 1: #<MITO.CLASS.COLUMN:COLUMN-STANDARD-EFFECTIVE-SLOT-DEFINITIONS MITO.DAO.MIXIN::UPDATED-AT>
2. 2: #<MITO.CLASS.COLUMN:COLUMN-STANDARD-EFFECTIVE-SLOT-DEFINITIONS MITO.DAO.MIXIN::SYNCED>
3. 3: #<MITO.CLASS.COLUMN:COLUMN-STANDARD-EFFECTIVE-SLOT-DEFINITIONS MITO.DAO.MIXIN::ID>
4. 4: #<MITO.CLASS.COLUMN:COLUMN-STANDARD-EFFECTIVE-SLOT-DEFINITIONS COMMON-LISP-USER::NAME>
> 
4 

The object is a STANDARD-OBJECT of type MITO.CLASS.COLUMN:COLUMN-STANDARD-EFFECTIVE-SLOT-DEFINITIONS.
0. SOURCE: NIL
1. NAME: NAME
2. INITFORM: NIL
3. INITFUNCTION: NIL
4. INITARGS: (:NAME)
5. %TYPE: T
6. %DOCUMENTATION: NIL
7. %CLASS: #<MITO.DAO.TABLE:DAO-TABLE-CLASS COMMON-LISP-USER::C1>
8. ACCESSOR-FLAGS: 15
9. INFO: #S(SB-PCL::SLOT-INFO
            :TYPECHECK NIL
            :ALLOCATION :INSTANCE
            :LOCATION 4
            :READER #<FUNCTION (LAMBDA (&REST SB-PCL::ARGS)
                                 :IN
                                 SB-PCL::INITIALIZE-INTERNAL-SLOT-FUNCTIONS) {1003B57B7B}>
            :WRITER #<FUNCTION (LAMBDA (&REST SB-PCL::ARGS)
                                 :IN
                                 SB-PCL::INITIALIZE-INTERNAL-SLOT-FUNCTIONS) {1003B57BEB}>
            :BOUNDP #<FUNCTION (LAMBDA (&REST SB-PCL::ARGS)
                                 :IN
                                 SB-PCL::INITIALIZE-INTERNAL-SLOT-FUNCTIONS) {1003B57C5B}>
            :MAKUNBOUND #<FUNCTION (LAMBDA (&REST SB-PCL::ARGS)
                                     :IN
                                     SB-PCL::INITIALIZE-INTERNAL-SLOT-FUNCTIONS) {1003B57CCB}>)
10. ALLOCATION: :INSTANCE
11. ALLOCATION-CLASS: #<MITO.DAO.TABLE:DAO-TABLE-CLASS COMMON-LISP-USER::C1>
12. LOCATION: 4
13. COL-TYPE: (OR :NULL :TEXT)
14. REFERENCES: NIL
15. PRIMARY-KEY: NIL
16. GHOST: NIL
> 
q
; No values
CL-USER> 

In particular, notice that now we can properly use the class-slots function and get the runtime information we want without the workaround mentioned in the issue.

CL-USER> (closer-mop:class-slots (find-class 'c1))
(#<MITO.CLASS.COLUMN:COLUMN-STANDARD-EFFECTIVE-SLOT-DEFINITIONS MITO.DAO.MIXIN::CREATED-AT>
 #<MITO.CLASS.COLUMN:COLUMN-STANDARD-EFFECTIVE-SLOT-DEFINITIONS MITO.DAO.MIXIN::UPDATED-AT>
 #<MITO.CLASS.COLUMN:COLUMN-STANDARD-EFFECTIVE-SLOT-DEFINITIONS MITO.DAO.MIXIN::SYNCED>
 #<MITO.CLASS.COLUMN:COLUMN-STANDARD-EFFECTIVE-SLOT-DEFINITIONS MITO.DAO.MIXIN::ID>
 #<MITO.CLASS.COLUMN:COLUMN-STANDARD-EFFECTIVE-SLOT-DEFINITIONS COMMON-LISP-USER::NAME>)

@daninus14 daninus14 marked this pull request as draft October 31, 2024 22:23
@daninus14
Copy link
Contributor Author

Work is in progress for the mito.dao.* package classes

…ach taken to dao-table-view and dao-table-mixin.

The actual definitions are in dao-table-column, named dao-table-column-standard-effective-slot-definitions
…definition to the effective slot class definition

- changed the reader to be an accessor to facilitate the change
@daninus14
Copy link
Contributor Author

Hi, please take a look at table-column-references.

I changed it in src/core/class/column.lisp to be an accessor instead of a reader so that I could copy the value from the direct class slot definition to the effective class slot definition in src/core/class/table.lisp. It's in the last commit hash 1e8e52b34d097a70cb5c1a941a71635d5d0da150.

Besides that there were no changes to how things worked. I've basically copied over to the effective slot the contents of the following slots:

  • inflate
  • deflate
  • references
  • ghost-slot-p
  • col-type
  • primary-key-p

I think that's everything that was defined in the direct slot definitions.

Is there anything else that needs to be checked?

So with this everything should be working now.

We should now be able to replace mito.class.table:table-column-slots with c2mop:class-slots and we can remove the helper functions for mito.class.table:table-column-slots as well.

@daninus14 daninus14 marked this pull request as ready for review November 2, 2024 21:23
@daninus14
Copy link
Contributor Author

Fixed a test which was missing a :col-type slot option and was failing

@daninus14
Copy link
Contributor Author

daninus14 commented Nov 2, 2024

So basically this is ready to be merged if it makes sense to you

@daninus14
Copy link
Contributor Author

I had to add some extra checks for certain types of slots which do not have a col-type though they are still valid and they were producing errors. Now the col-type should properly show up in the effective slots produced by closer-mop:class-slots when they should be there.

@daninus14
Copy link
Contributor Author

Hi, I'm just following up here.

Just a simple explanation of what this PR is doing. Effective slots are the slots available in the class once the class is initialized. Direct slots are when the class is being initialized, but not after initialization. What we accomplish with this PR is that when looking at a class and inspecting it, we can see the slot options and information in the runtime class that were added during the class definition.

For example, doing (find-class my-class) and inspecting that, and the corresponding slots, will show col-type and anything else defined during the defclass. It just keeps the information.

Is there any information or questions I can answer about this PR?

@daninus14
Copy link
Contributor Author

Just to add more context, this effective slot definition was missing, and the current code is doing all sorts of hacks and workarounds to get functionality that is built in by Common Lisp.

For example:

We should now be able to replace mito.class.table:table-column-slots with c2mop:class-slots and we can remove the helper functions for mito.class.table:table-column-slots as well.

CL already provides a class-slots function. The reason mito uses mito.class.table:table-column-slots was because of information on the slots being "lost". But that was because only direct slot definitions were provided, and not effective slot definitions, which is what this PR accomplishes. This would simplify the mito code, and make it more robust since it uses built in CL functionality instead of reinventing the wheel.

@daninus14
Copy link
Contributor Author

Just to provide more information on the benefits of this.

today I needed to use find-child-columns

https://github.com/fukamachi/mito/blob/c337a17bc9ff6dc0ea9017601d829aab99ec5e2e/src/core/class/table.lisp#L296C1-L307C14

Which is defined as

(defun find-child-columns (table slot)
  (let (results)
    (map-all-superclasses
      (lambda (class)
        (when (slot-exists-p class 'parent-column-map)
          (maphash (lambda (child parent)
                     (when (eq parent (c2mop:slot-definition-name slot))
                       (push child results)))
                   (slot-value class 'parent-column-map))))
      table)
    results))

But if we just use the built in CL functionality of effective class slots, we can replace that with the simpler

(defun find-child-columns (table slot)
  (let (results)
    (when (slot-exists-p table 'parent-column-map)
      (maphash (lambda (child parent)
                 (when (eq parent (c2mop:slot-definition-name slot))
                   (push child results)))
               (slot-value table 'parent-column-map)))
    results))

Every call to map-all-superclasses is basically unnecessary and code will be faster and correct. Subclasses can change slots that are inherited, therefore map-all-superclasses is actually incorrect for computing a class's direct slots. That's what closer-mop:class-slots is meant to do.

Copy link
Owner

@fukamachi fukamachi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great suggestion, and really sorry for the delay.

Could you add this method definition also for dao-table-view (src/core/dao/view.lisp) to take advantage of your changes?

  (defmethod c2mop:effective-slot-definition-class ((class dao-table-view) &key)
    'dao-table-column-standard-effective-slot-definitions)

@daninus14
Copy link
Contributor Author

Great suggestion, and really sorry for the delay.

Could you add this method definition also for dao-table-view (src/core/dao/view.lisp) to take advantage of your changes?

  (defmethod c2mop:effective-slot-definition-class ((class dao-table-view) &key)
    'dao-table-column-standard-effective-slot-definitions)

Hi, that's there already as:

(defmethod c2mop:effective-slot-definition-class ((class dao-table-view) &rest initargs)
  (declare (ignorable initargs))
  (find-class 'mito.dao.column:dao-table-column-standard-effective-slot-definitions))

https://github.com/daninus14/mito/blob/9403930441ae8fce5baf3c22545ab2e52e1277b5/src/core/dao/view.lisp#L24-L26

Not sure why I had to add the find-class. I think it was giving me some issue without it. I just cleaned it up and it works without it. Just pushed the changes

@daninus14
Copy link
Contributor Author

it now looks like: https://github.com/daninus14/mito/blob/a9e020bb7070042b90a2cc4774928181409cd7de/src/core/dao/view.lisp#L24-L26

(defmethod c2mop:effective-slot-definition-class ((class dao-table-view) &rest initargs)
  (declare (ignorable initargs))
  'dao-table-column-standard-effective-slot-definitions)


t/test.db
.qlot/
.emacs*
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this for?

Suggested change
.emacs*

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, that just ignores emacs desktop and settings files that emacs sometimes adds automatically to the project, just to keep them out of the git workflow. I can remove it as well, just let me know. It's a convenience to be able to do git add . instead of having to add file by file

daninus14 and others added 4 commits December 3, 2025 05:51
Co-authored-by: Eitaro Fukamachi <e.arrows@gmail.com>
Co-authored-by: Eitaro Fukamachi <e.arrows@gmail.com>
Co-authored-by: Eitaro Fukamachi <e.arrows@gmail.com>
Co-authored-by: Eitaro Fukamachi <e.arrows@gmail.com>
@fukamachi fukamachi merged commit eb433e4 into fukamachi:master Dec 3, 2025
1 check failed
@fukamachi
Copy link
Owner

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants