tags:

views:

62

answers:

1

I can't see what I am doing wrong, as the files are in the correct order. In this case it is:

  1. BaseDAO.fs
  2. CreateDatabase.fs

They are in the same namespace, but even when I had them in different modules, and opened the module in CreateDatabase the same error.

The error is:

Error   1   The value or constructor 'execNonQuery' is not defined  

I am trying to inherit BaseDAO and use a member that will be common to several files, and I don't see why I get the error above.

namespace RestaurantServiceDAO

open MySql.Data.MySqlClient

type BaseDAO() =
    let connString = @"Server=localhost;Database=mysql;Uid=root;Pwd=$$$$;"
    let conn = new  MySqlConnection(connString)

    member self.execNonQuery(sqlStr) =
        conn.Open()
        let comm = new MySqlCommand(sqlStr, conn, CommandTimeout = 10)
        comm.ExecuteNonQuery |> ignore
        comm.Dispose |> ignore

The type that does inherit is here, and execNonQuery is not defined.

namespace RestaurantServiceDAO

open MySql.Data.MySqlClient

type CreateDatabase() =
    inherit BaseDAO()

    let createRestaurantTable conn =
        execNonQuery "CREATE TABLE restaurant(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100), cur_timestamp TIMESTAMP(8))"
+5  A: 

In F#, inherited members (as well as members defined in the current type) cannot be called implicitly just by the name of the member - you need to refer to the instance of the type somehow. In your case, you can use the base keyword. The following should work:

type CreateDatabase() = 
    inherit BaseDAO() 
    let createRestaurantTable conn = 
        base.execNonQuery "..."

[EDIT] This works only if createRestaurantTable is a member - not a function declared using let (as in the example above). The reason is that F# compiler doesn't allows caputring base in a closure and it interprets the sample above as a closure. You can turn it into member and write:

type CreateDatabase() = 
    inherit BaseDAO() 
    private member x.createRestaurantTable conn = 
        x.execNonQuery "..."

[/EDIT]

Alternatively, you can also name the current instance of the type using as self (which is similar to specifying the instance using member self.Foo() = .. in member declarations. This also allows you to call members of the current type from the constructor:

type CreateDatabase() as self = 
    inherit BaseDAO() 
    let createRestaurantTable conn = 
        self.execNonQuery "..."

I'd prefer the base keyword if that's possible (because refering to the current instance in the constructor causes all sorts of headaches to the compiler).

Tomas Petricek
I couldn't use base.execNonQuery, as it complained about closures,but I did turn them into members and that solved my problem. Thank you
James Black
@James: You're right - `base` cannot be used inside `let`-bound functions. This is a bit unfrotunate - adding `as self` may be another alternative (it generates some runtime checks to make sure that the initialization is correct and that you don't use `self` before the class is fully initialized, but that shouldn't be a big problem).
Tomas Petricek