Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve get-type-of #69

Open
mnieper opened this issue Jul 8, 2023 · 7 comments
Open

Improve get-type-of #69

mnieper opened this issue Jul 8, 2023 · 7 comments

Comments

@mnieper
Copy link

mnieper commented Jul 8, 2023

The Cookbook should (as it says) emphasize modern solutions. I wouldn't call the solution

(define (type-of obj)

modern because it loops through a list effectively built at runtime, preventing compiler optimizations. A "modern" solution would use modern macros. :) Or a hardcoded cond expression where the compiler can inline the primitives.

An independent question: What is a compelling use case for the procedure?

@jcubic
Copy link
Contributor

jcubic commented Jul 8, 2023

The use of this procedure is for multiple dispatch in #60.

Also note, that this has to be runtime I don't think that will be any use of a procedure like this that is optimized by the compiler (But I may be wrong on this).

@mnieper
Copy link
Author

mnieper commented Jul 8, 2023

The use of this procedure is for multiple dispatch in #60.

Then you would do a double dispatch. First you would dispatch according to the type to retrieve a symbol and then you would dispatch according to the symbol to pick a specialized procedure. This sounds like a recipe for Python-like performance to me...

Also note, that this has to be runtime I don't think that will be any use of a procedure like this that is optimized by the compiler (But I may be wrong on this).

If a compiler sees code like

(cond
  [(pair? ...) ...]
  [(string? ...) ...]
  [(fixnum? ...) ...]
  ...)

it may be able to optimize it with knowledge of its tagging system. In fact, an implementation's internal tagging system is like a type-of procedure.

@lassik
Copy link
Member

lassik commented Jul 8, 2023

Is there any problem where you'd use a homegrown type-of in the hot path? It sounds exceedingly unlikely.

@lassik
Copy link
Member

lassik commented Jul 8, 2023

What is a compelling use case for the procedure? Interactive use, most likely. For "production use" you'd rely on a built-in (and non-standard) type system or object system of a Scheme implementation.

@mnieper
Copy link
Author

mnieper commented Jul 9, 2023

When would you need the procedure interactively? Instead of printing the type-of of an object, I can just print the object itself, which also shows me the type.

@jcubic
Copy link
Contributor

jcubic commented Jul 10, 2023

It's useful to have a type as a symbol or a string. Because you can create Alist where keys are types and have a logic based on that. Sometimes you don't want to hardcode typechecking to every code you have, and often you need type as value.

(define l (list
            (cons 'string (lambda (x)
                            (display (string-append x " is a string"))
                            (newline)))))

(let ((x "something"))
  ((cdr (assoc (type-of x) l)) x))

The same can be done with hashtable. I'm not sure about Scheme but in language like JavaScript you often change swith..case (scheme cond or case) with assoc table so to make the code cleaner and probably also faster.

Another usecase if you want to throw exception with type of the value you have, if you have some kind of typechecking. The same you don't want in every place use cond with individual typechecking.

@mnieper
Copy link
Author

mnieper commented Jul 10, 2023

It's useful to have a type as a symbol or a string. Because you can create Alist where keys are types and have a logic based on that. Sometimes you don't want to hardcode typechecking to every code you have, and often you need type as value.

(define l (list
            (cons 'string (lambda (x)
                            (display (string-append x " is a string"))
                            (newline)))))

(let ((x "something"))
  ((cdr (assoc (type-of x) l)) x))

This is IMHO bad code. What the code effectively does is a double dispatch where a single dispatch would suffice. The code first cooks up a symbol by iterating through possible type predicates and then has to iterate through the list of possible symbols.

The same can be done with hashtable. I'm not sure about Scheme but in language like JavaScript you often change swith..case (scheme cond or case) with assoc table so to make the code cleaner and probably also faster.

The compiler would have to understand the double dispatching and recreate a static conditional to get back the efficiency of a hard-coded conditional (compilers know how to optimize switch statements very well).

If you want "cleaner" code, make type-of a macro type-case (or whatever), and don't use runtime dispatch tables.

Another usecase if you want to throw exception with type of the value you have, if you have some kind of typechecking. The same you don't want in every place use cond with individual typechecking.

It is usually better to throw the value and not a symbol representing the type. The value is more informative and you will also get something for user-defined (record) types.

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

No branches or pull requests

3 participants