Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Generic Programming Must Go (youtube.com)
15 points by jacques_chirac on July 8, 2015 | hide | past | favorite | 2 comments


My favourite talk from DConf 2015. It is about the tension in the compile-time realm between:

- static interfaces (C++ concepts, Rust traits, Haskell typeclasses... or whatever name they have in a particular language)

- and the more adhoc compile-time duck-typing (eg: D static if, C++ expression SFINAE). Alexandrescu is arguing for the latter being more useful.

I can only agree with him considering the sheer difficulty of making reusable generic code that squarely fits a problem domain.

Programmers interested in meta-programming and reuse would probably enjoy the talk.


All of the examples he shows fall into one of two classes:

-Check whether a type implements a method; if so, do that method.

-Check whether a type implements a method; if so, branch on the success / failure of that method.

Both of these examples can be implemented using interfaces with default implementations, in a way which avoids having to explicitly branch at every call-site. You have to rely on the compiler to do inlining, constant-folding and dead code elimination if you want the same performance as the method in the video, but it gives shorter (and arguably simpler) code and useful type signatures.

To-wit, here's a proof of concept in Haskell:

  import Debug.Trace                                                            
                                                                                
  data VoidPtr = VoidPtr | Null                                                 
                                                                                
  data WithDealloc = WithDealloc                                                
                                                                                
  data NoDealloc = NoDealloc                                                    
                                                                                
  class Allocator a where                                                       
    alloc :: a -> VoidPtr                                                       
    alignment :: a -> Int                                                       
                                                                                
  class Allocator a => Dealloc a where                                          
    dealloc :: a -> VoidPtr -> ()                                               
    dealloc _ _ = trace "dummy dealloc" ()                                      
                                                                                
  instance Allocator WithDealloc where                                          
    alloc _ = VoidPtr                                                           
    alignment _ = 0                                                             
                                                                                
  instance Dealloc WithDealloc where                                            
    dealloc _ _ = trace "specialized dealloc" ()                                
                                                                                
  instance Allocator NoDealloc where                                            
    alloc _ = VoidPtr                                                           
    alignment _ = 0                                                             
                                                                                
  class Allocator a => Owns a where                                             
    owns :: a -> VoidPtr -> Bool                                                
    owns _ _ = False                                                            
                                                                                
  data BackupAllocator a b = BackupAllocator a b                                
                                                                                
  instance (Allocator a, Allocator b) => Allocator (BackupAllocator a b) where  
    alloc (BackupAllocator a b) =                                               
      case x of                                                                 
        VoidPtr -> x                                                            
        Null -> alloc b                                                         
      where x = alloc a                                                         
    alignment (BackupAllocator a b) = min (alignment a) (alignment b)           
                                                                                
  instance (Owns a, Dealloc a, Dealloc b) => Dealloc (BackupAllocator a b) where
    dealloc (BackupAllocator p f) b                                             
      | p `owns` b = dealloc p b                                                
      | otherwise  = dealloc f b                                                
                                                                                
  instance Owns WithDealloc                                                     
  instance Owns NoDealloc                                                       
  instance Dealloc NoDealloc                                                    
                                                                                
  test = (a, b)                                                                 
    where a = dealloc (BackupAllocator WithDealloc NoDealloc) VoidPtr -- Dummy  
          b = dealloc (BackupAllocator NoDealloc WithDealloc) VoidPtr -- Specialized




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: