The code in this gist tries to find a way to have pseudo "multi methods" in C++ by extending a visitor interface, hence the title: extending library visitor for user-defined types with macros. The idea is this: you want to implement the Visitor pattern over a class hierarchy defined in a library. But users of the library might have their own classes, extending the hierarchy, forcing your visitor to know about them. My proposal: a small macros that extend the visitor
🏳️⚧️
While the previous gist documented my attempt at finding a working solution, this one provides a small working example.
Here, the library code declares classes A and B both inheriting form a base class Base. A Visitor is introduced, and both A and B have a apply method that calls the appropriate visitor method.
The client introduces a new class C that also inherits from base, and
which is able to use a Visitor-derived class on any Base*
pointer,
be it a A, a B or a C under the hood.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE ConstraintKinds #-} | |
{-# LANGUAGE DataKinds #-} | |
{-# LANGUAGE FlexibleContexts #-} | |
{-# LANGUAGE FlexibleInstances #-} | |
{-# LANGUAGE MultiParamTypeClasses #-} | |
{-# LANGUAGE ParallelListComp #-} | |
{-# LANGUAGE TypeFamilies #-} | |
{-# LANGUAGE TypeOperators #-} | |
{-# LANGUAGE UndecidableInstances #-} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE DataKinds #-} | |
{-# LANGUAGE FlexibleContexts #-} | |
{-# LANGUAGE FlexibleInstances #-} | |
{-# LANGUAGE TypeFamilies #-} | |
{-# LANGUAGE TypeOperators #-} | |
import Data.Proxy | |
import GHC.TypeLits |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE FlexibleContexts #-} | |
{-# LANGUAGE FlexibleInstances #-} | |
{-# LANGUAGE FunctionalDependencies #-} | |
{-# LANGUAGE UndecidableInstances #-} | |
-- no data kinds, pure type level | |
-- let's start by defining booleans and numbers | |
data True |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{"type":"http-log","timestamp":"2020-03-31T00:05:40.203+0000","level":"error","detail":{"operation":{"user_vars":{"x-hasura-role":"admin"},"error":{"internal":{"statement":"DO $$ DECLARE r RECORD; BEGIN FOR r IN (SELECT routine_name FROM information_schema.routines WHERE specific_schema = 'hdb_views' ORDER BY routine_name) LOOP EXECUTE 'DROP FUNCTION hdb_views.' || quote_ident(r.routine_name) || '() CASCADE'; END LOOP; END $$; ","prepared":false,"error":{"exec_status":"FatalError","hint":null,"message":"cannot execute DROP FUNCTION in a read-only transaction","status_code":"25006","description":null},"arguments":[]},"path":"$.args[0].args","error":"postgres query error","code":"unexpected"},"request_id":"51d1a76d-8688-4905-a913-f1be94bc8df5","response_size":566,"query":{"args":[{"args":{"cascade":false,"check_metadata_consistency":null,"sql":"SELECT\n COALESCE(Json_agg(Row_to_json(info)), '[]' :: json) AS tables\nFROM (\n SELECT\n pgn.nspname as table_schema,\n pgc.relname as table_name, |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE DeriveFunctor #-} | |
{-# LANGUAGE LambdaCase #-} | |
import Control.Applicative (liftA2) | |
import Data.Char | |
import Data.Foldable (for_) | |
import Data.Functor | |
import qualified Data.HashMap.Strict as M | |
import Data.List (intercalate) | |
import Prelude hiding (any) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE AllowAmbiguousTypes #-} | |
{-# LANGUAGE ScopedTypeVariables #-} | |
{-# LANGUAGE TypeApplications #-} | |
import Data.Proxy | |
import Data.Typeable | |
contains :: forall a b. (Typeable a, Typeable b) => Bool | |
contains = go typeB | |
where typeA = typeRep (Proxy :: Proxy a) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE AllowAmbiguousTypes #-} | |
{-# LANGUAGE DataKinds #-} | |
{-# LANGUAGE PolyKinds #-} | |
{-# LANGUAGE TypeFamilies #-} | |
{-# LANGUAGE TypeOperators #-} | |
{-# LANGUAGE UndecidableInstances #-} | |
import Data.Kind (Type) | |
import Data.Type.Bool |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
all: | |
ghc --version | |
ghc -Wredundant-constraints -Werror -O0 Main.hs | |
ghc -Wredundant-constraints -Werror -O2 Main.hs |
OlderNewer