mongo.cr icon indicating copy to clipboard operation
mongo.cr copied to clipboard

Undefined method [] for Nil:Class during compilation

Open elrok123 opened this issue 8 years ago • 6 comments

Getting a problem when trying to create an instance of a collection, I can't get past the compilation as I think the compiler is trying to account for the client instance possibly being 'Nil' and there being no method handlers for '[]' on the object which is very odd, as I have validation expressions outside the object. If someone could give a hand on why this is happening, that'd be great.

Implementation:

 class MxMongo                                                                                       
 -»»»# Initialise everything we need                                                                 
 -»»»def initialize(host : String, username : String, password : String, port : String)              
 -»»»-»»»@client = Nil                                                                               
 -»»»-»»»@database = "aggregation"                                                                   
 -»»»-»»»self.connect(host, username, password, port)                                                
 -»»»end                                                                                             
 -»»»                                                                                                
 -»»»# Connect to the database                                                                       
 -»»»def connect(host : String, username : String, password : String, port : String)                 
 -»»»-»»»@client = Mongo::Client.new "mongodb://#{username}:#{password}@#{host}:#{port}/#{@database}"
 -»»»-»»»return @client                                                                              
 -»»»end                                                                                             
                                                                                                     
 -»»»# Get an instance of the database                                                               
 -»»»def get_instance                                                                                
 -»»»-»»»if @client.not_nil! && db.not_nil!                                                          
 -»»»-»»»-»»»return @client                                                                          
 -»»»-»»»else                                                                                        
 -»»»-»»»-»»»return Nil                                                                              
 -»»»-»»»end                                                                                         
 -»»»end                                                                                             
                                                                                                     
 -»»»def get_collection(collection : String)                                                         
 -»»»-»»»if [email protected]? && !collection.nil?                                                        
 -»»»-»»»-»»»client = @client                                                                        
 -»»»-»»»-»»»return client.not_nil![collection] if collection.not_nil!                               
 -»»»-»»»else                                                                                        
 -»»»-»»»-»»»return Nil                                                                              
 -»»»-»»»end                                                                                         
 -»»»end                                                                                             
 end                                                                                                 

Error I recieve:

                                                                                                                      
test = mongo_client.get_collection("aggregation")                                                                     
                    ^~~~~~~~~~~~~~                                                                                    
                                                                                                                      
in classes/init_mongo.cr:27: undefined method '[]' for Nil:Class (compile-time type is (Mongo::Client | Nil:Class))   
                                                                                                                      
   return client.not_nil![collection] if collection.not_nil!                                                          
                         ^                                                                                            
                                                                                                                      
================================================================================                                      
                                                                                                                      
Nil:Class trace:                                                                                                      
                                                                                                                      
  /usr/lib/crystal/object.cr:156                                                                                      
                                                                                                                      
      def not_nil!                                                                                                    
          ^~~~~~~~                                                                                                    
                                                                                                                      
  /usr/lib/crystal/object.cr:157                                                                                      
                                                                                                                      
        self                                                                                                          
        ^~~~                                                                                                          


Apologies for the formatting, copied from vim

elrok123 avatar Jul 10 '17 17:07 elrok123

i think you meant to write it as @client not just client

datanoise avatar Jul 10 '17 18:07 datanoise

@datanoise Nope, unfortunately not, I offload the @client instance to a local var, due to the read write differences between instance vars and local vars, I've had issues in the past with Crystal not allowing me to set instance vars etc, so tried offloading to a local var just to see if that fixed it.

If you read the code though, you can see here that I definitely define the client var before being used:

-»»»def get_collection(collection : String)                                                         
-»»»-»»»if [email protected]? && !collection.nil?                                                        
-»»»-»»»-»»»client = @client                                                                        
-»»»-»»»-»»»return client.not_nil![collection] if collection.not_nil!                               
-»»»-»»»else                                                                                        
-»»»-»»»-»»»return Nil                                                                              
-»»»-»»»end                                                                                         
-»»»end

elrok123 avatar Jul 11 '17 10:07 elrok123

why Nil is uppercased? is it intentional?

datanoise avatar Jul 11 '17 14:07 datanoise

In this instance they would resolve to the same thing anyway, no? As it's a return value, and Nil is just the class, and nil is an global instance of the Nil class. Correct me if I'm wrong.

elrok123 avatar Jul 11 '17 14:07 elrok123

No, they are not the same thing. 'Nil' is the class type (in this case struct type) and nil is its singleton instance. Nil.not_nil! == Nil as for any other object, but nil.not_nil! will raise an exception. That means that your @client variable could be either an instance of Mongo::Client class or Nil class type and the compiler correctly detects that Nil class type has no method [] defined.

datanoise avatar Jul 11 '17 14:07 datanoise

Ah awesome, thanks for the explanation, was curious what was actually going on under the hood, as I've experienced something similar to this I think, and I did not even consider the difference between Nil and nil

elrok123 avatar Jul 11 '17 15:07 elrok123