datanoise / mongo.cr

Crystal binding for MongoDB C Driver
MIT License
97 stars 35 forks source link

Undefined method [] for Nil:Class during compilation #25

Open elrok123 opened 7 years ago

elrok123 commented 7 years ago

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 !@client.nil? && !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

datanoise commented 7 years ago

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

elrok123 commented 7 years ago

@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 !@client.nil? && !collection.nil?                                                        
 -»»»-»»»-»»»client = @client                                                                        
 -»»»-»»»-»»»return client.not_nil![collection] if collection.not_nil!                               
 -»»»-»»»else                                                                                        
 -»»»-»»»-»»»return Nil                                                                              
 -»»»-»»»end                                                                                         
 -»»»end
datanoise commented 7 years ago

why Nil is uppercased? is it intentional?

elrok123 commented 7 years ago

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.

datanoise commented 7 years ago

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.

elrok123 commented 7 years ago

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