Add an "abstract" method to (an F#) record - f#

I have created the following record in an attempt to translate a C# class to F#:
type Days = Days of int
type Value = Value of int
type Item = {
Name: string
Expires: Days
Value: Value
}
Thing is I also need every Item to have a... "way", to run another function, yet not defined, handleDevalue, which acts on the item itself to manipulate the item's Value value.
The handleDevalue function is dependent on the Expires property of the item and thus each item's implementation of it would be different, with the only common thread being the function's name and signature (Item -> Item).
On the C# code I'm translating this method was defined as abstract on the Item class and overriden on every item instantiated (where every item is a subclass inheriting from Item).
What I've tried, unsuccessfully till now:
Add an abstract method on the record: ...} with abstract handleDevalue: Item -> Item.
1.1 Reason for failure: IDE tells me "abstract can't be added here as an augmentation" (or something close to the same effect). (I'm not F#-savvy enough to even know what it means, but the compiler won't let it compile so... no).
Add handleDevalue as a function on the record: {... HandleDevalue: Item -> Item...}.
2.1. Reason for failure: this function is dependent on the Expires property. Apparently a record's fields are mutually independent of each other, and besides... how will the function "know" which item to act on (it's supposed to act on the item itself)? The this keyword is not allowed when implementing a function when "instantiating" a record (i.e. no {...handleDevalue = fun this -> <some implementation code here>).
I could remember to define the function on every item I create (I should anyway), but that's not using the type system to my advantage.
I want the compiler to force me to implement the function and remind me if I don't.
With these ways failing I'm out of ideas how to move forward.
Thanks for any advice in advance.

I'm not really sure what you are trying to accomplish here, but I'll give it a shot.
Why not do something similar to this, using a discriminated union instead of inheritance?
type Days = Days of int
type Value = Value of int
type Item = {
name: string
expires: Days
value: Value
}
type ItemType =
| FooItem of Item
| BarItem of Item
| BazItem of Item
// ...
let deValue item =
match item with
| FooItem i ->
{
name = i.name
expires = i.expires -1
value = i.value -1
} |> FooItem
| BarItem i ->
{
name = i.name
expires = i.expires -1
value = i.value -10
} |> BarItem
| // etc

Think about what actually happens in the C# program.
You have several different implementations of handleDevalue, and every item instance has one of those implementations associated with it. But what determines which one goes with which item? Well, this is determined by the specific descendant class that the item is. Ok, but what determines which descendant class gets instantiated?
Somewhere, at some point, there must be a place that picks a descendant class somehow. Let's assume it looks something like this:
class Item { public abstract int handleDevalue() { ... } }
class FooItem : Item { public override int handleDevalue() { ... } }
class BarItem : Item { public override int handleDevalue() { ... } }
public Item createItem(string name, Days expires, Value value) {
if (foo) return new FooItem(name, expires, value)
else return BarItem(name, expires, value)
}
So, look what's happening: ultimately, whoever creates the items is choosing which handleDevalue implementation ends up being used, and then that implementation gets attached to the item instance via the method table.
Now that we know this, we can do the same thing in F#. We'd just need to make attaching of the implementation explicit:
type Item = {
Name : string
Expires : Days
Value : Value
handleDevalue : Item -> Item
}
let handleDevalueFoo item = ...
let handleDevalueBar item = ...
let createItem name expires value = {
Name = name
Expires = expires
Value = value
handleDevalue = if foo then handleDevalueFoo else handleDevalueBar
}

Related

Searching a List of objects for a particular object in dart using "where"

I would like to obtain an object from a List based on a specific search criteria of its member variable
this is the code I am using
class foo
{
foo(this._a);
int _a;
}
List<foo> lst = new List<foo>();
main()
{
foo f = new foo(12);
lst.add(f);
List<foo> result = lst.where( (foo m) {
return m._a == 12;
});
print(result[0]._a);
}
I am getting the error and not sure how to resolve this
Uncaught exception:
TypeError: Instance of 'WhereIterable<foo>': type 'WhereIterable<foo>' is not a subtype of type 'List<foo>'
I am trying to search for an object whose member variable a == 12. Any suggestions on what I might be doing wrong ?
The Iterable.where method returns an iterable of all the members which satisfy your test, not just one, and it's a lazily computed iterable, not a list. You can use lst.where(test).toList() to create a list, but that's overkill if you only need the first element.
You can use lst.firstWhere(test) instead to only return the first element, or you can use lst.where(test).first to do effectively the same thing.
In either case, the code will throw if there is no element matched by the test.
To avoid throwing, you can use var result = lst.firstWhere(test, orElse: () => null) so you get null if there is no such element.
Another alternative is
foo result;
int index = lst.indexWhere(test);
if (index >= 0) result = lst[index];
The answer is simple. Iterable.where returns an Iterable, not a List. AFAIK this is because _WhereIterable does its computations lazily.
If you really need to return a List, call lst.where(...).toList().
Otherwise, you can set result to be an Iterable<foo>, instead of a List<foo>.
or you can go crazy and do this:
bool checkIfProductNotFound(Map<String, Object> trendingProduct) {
bool isNotFound = this
._MyProductList
.where((element) => element["id"] == trendingProduct["id"])
.toList()
.isEmpty;
return isNotFound ;
}

Object == Object2 when stored in List<T> but not when object in IEnumerable<T> - WHY?

Using ASP MVC5 and EF6.
I had a curious case the other day when I was looking to have different behaviour when a foreach-loop got to the last element.
The loop wouldn't enter if-condition comparing the object with the result from .Last()-method on the collection.
The collection I was iterating over was something like:
public class CollectionClass{
IEnumerable<TestClass1> CollectionA
IEnumerable<TestClass2> CollectionB
}
My code was something like:
DbContext db = new DbContext(); //just for illustration, not actual code
CollectionClass cc = new CollectionClass {
CollectionA = db.TestClasses1,
CollectionB = db.TestClasses2
};
//(TestClasses1 and TestClasses2 are DbSet<T> properties of my DbContext.
foreach(TestClass1 tc1 in cc.CollectionA)
{
if (tc1 == cc.CollectionA.Last()){ //<---NEVER enters in here!!
//doStuff
}
else{
//doOtherStuff
}
}
With the code above, the loop never entered into the if-condition, even for the last element, which one would expect.
But when changed my CollectionClass to:
public class CollectionClass{
List<TestClass1> CollectionA
List<TestClass2> CollectionB
}
and instantiated the CollectionClass-object like this:
CollectionClass cc = new CollectionClass {
CollectionA = db.TestClasses1.ToList(),
CollectionB = db.TestClasses2.ToList()
}; //Added .ToList()
the loop entered into the first if-condition at the last iteration as I expected.
Why this difference? Why did the equals-operator (==) evaluate to TRUE when the object had been stored in a List and FALSE when the object was stored in an IEnumerable?
I know that IEnumerable is an interface -- is that what makes the difference?
I even did an explicit test in the sorts of:
var obj1 = cc.CollectionA.Last();
var obj2 cc.CollectionA.Last();
bool result = obj1 == obj2; //result = FALSE
and the result was FALSE.
I think it's because in first example you get two objects from database. First from iteration and second from call to Last().
In second example all objects are created at the time you assign collections to CollectionA and CollectionB (you call ToList()).
It is because you are not allowed to use Last and LastOrDefault on DbSet objects. Instead you should use OrderByDescending(t=>t.ID).First()

Passing query parameters in Dapper using OleDb

This query produces an error No value given for one or more required parameters:
using (var conn = new OleDbConnection("Provider=..."))
{
conn.Open();
var result = conn.Query(
"select code, name from mytable where id = ? order by name",
new { id = 1 });
}
If I change the query string to: ... where id = #id ..., I will get an error: Must declare the scalar variable "#id".
How do I construct the query string and how do I pass the parameter?
The following should work:
var result = conn.Query(
"select code, name from mytable where id = ?id? order by name",
new { id = 1 });
Important: see newer answer
In the current build, the answer to that would be "no", for two reasons:
the code attempts to filter unused parameters - and is currently removing all of them because it can't find anything like #id, :id or ?id in the sql
the code for adding values from types uses an arbitrary (well, ok: alphabetical) order for the parameters (because reflection does not make any guarantees about the order of members), making positional anonymous arguments unstable
The good news is that both of these are fixable
we can make the filtering behaviour conditional
we can detect the category of types that has a constructor that matches all the property names, and use the constructor argument positions to determine the synthetic order of the properties - anonymous types fall into this category
Making those changes to my local clone, the following now passes:
// see https://stackoverflow.com/q/18847510/23354
public void TestOleDbParameters()
{
using (var conn = new System.Data.OleDb.OleDbConnection(
Program.OleDbConnectionString))
{
var row = conn.Query("select Id = ?, Age = ?", new DynamicParameters(
new { foo = 12, bar = 23 } // these names DO NOT MATTER!!!
) { RemoveUnused = false } ).Single();
int age = row.Age;
int id = row.Id;
age.IsEqualTo(23);
id.IsEqualTo(12);
}
}
Note that I'm currently using DynamicParameters here to avoid adding even more overloads to Query / Query<T> - because this would need to be added to a considerable number of methods. Adding it to DynamicParameters solves it in one place.
I'm open to feedback before I push this - does that look usable to you?
Edit: with the addition of a funky smellsLikeOleDb (no, not a joke), we can now do this even more directly:
// see https://stackoverflow.com/q/18847510/23354
public void TestOleDbParameters()
{
using (var conn = new System.Data.OleDb.OleDbConnection(
Program.OleDbConnectionString))
{
var row = conn.Query("select Id = ?, Age = ?",
new { foo = 12, bar = 23 } // these names DO NOT MATTER!!!
).Single();
int age = row.Age;
int id = row.Id;
age.IsEqualTo(23);
id.IsEqualTo(12);
}
}
I've trialing use of Dapper within my software product which is using odbc connections (at the moment). However one day I intend to move away from odbc and use a different pattern for supporting different RDBMS products. However, my problem with solution implementation is 2 fold:
I want to write SQL code with parameters that conform to different back-ends, and so I want to be writing named parameters in my SQL now so that I don't have go back and re-do it later.
I don't want to rely on getting the order of my properties in line with my ?. This is bad. So my suggestion is to please add support for Named Parameters for odbc.
In the mean time I have hacked together a solution that allows me to do this with Dapper. Essentially I have a routine that replaces the named parameters with ? and also rebuilds the parameter object making sure the parameters are in the correct order.
However looking at the Dapper code, I can see that I've repeated some of what dapper is doing anyway, effectively it each parameter value is now visited once more than what would be necessary. This becomes more of an issue for bulk updates/inserts.
But at least it seems to work for me o.k...
I borrowed a bit of code from here to form part of my solution...
The ? for parameters was part of the solution for me, but it only works with integers, like ID. It still fails for strings because the parameter length isn't specifed.
OdbcException: ERROR [HY104] [Microsoft][ODBC Microsoft Access Driver]Invalid precision value
System.Data.Odbc. OdbcParameter.Bind(OdbcStatementHandle hstmt,
OdbcCommand command, short ordinal, CNativeBuffer parameterBuffer, bool allowReentrance)
System.Data.Odbc.OdbcParameterCollection.Bind(OdbcCommand command, CMDWrapper cmdWrapper, CNativeBuffer parameterBuffer)
System.Data.Odbc.OdbcCommand.ExecuteReaderObject(CommandBehavior behavior, string method, bool needReader, object[] methodArguments, SQL_API odbcApiMethod)
System.Data.Odbc.OdbcCommand.ExecuteReaderObject(CommandBehavior behavior, string method, bool needReader)
System.Data.Common.DbCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
Dapper.SqlMapper.QueryAsync(IDbConnection cnn, Type effectiveType, CommandDefinition command) in SqlMapper.Async.cs
WebAPI.DataAccess.CustomerRepository.GetByState(string state) in Repository.cs
var result = await conn.QueryAsync(sQuery, new { State = state });
WebAPI.Controllers.CustomerController.GetByState(string state) in CustomerController .cs
return await _customerRepo.GetByState(state);
For Dapper to pass string parameters to ODBC I had to specify the length.
var result = await conn.QueryAsync<Customer>(sQuery, new { State = new DbString { Value = state, IsFixedLength = true, Length = 4} });

Modeling database records as types

I'm rewriting a C# library in F# in which most of the classes map one-to-one with database tables (similar to ActiveRecord). I'm considering whether to use records or classes (maybe even DUs?). There's a fair amount of validation in the property setters to maintain invariants. What would be the best way to model this in F#? I don't want an object that violates business logic to be persisted to the database. Any ideas are welcome.
A few additional thoughts...
Is it better to move the invariants to an external 'controller' class? Coming from C# it feels wrong to allow an object that corresponds to a database record to contain anything that can't be saved to the database. I suppose because failing earlier seems better than failing later.
You can have your data in a record, and still keep the validation logic with the data type, by attaching methods to the record:
type Person =
{ First : string;
Last : string; } with
member x.IsValid () =
let hasValue = System.String.IsNullOrEmpty >> not
hasValue x.First && hasValue x.Last
let jeff = { First = "Jeff"; Last = "Goldblum" }
let jerry = { jeff with First = "Jerry" }
let broken = { jerry with Last = "" }
let valid = [jeff; jerry; broken]
|> List.filter (fun x -> x.IsValid())
The copy semantics for records are almost as convenient as setting a property. The validation doesn't happen on property set, but it's easy to filter a list of records down to only the valid ones.
This should actually be a good way for you to handle it. Having your validation logic in the constructor will give you piece of mind later on in your code because the object is immutable. This also opens up multi-threading possibilities.
Immutable Version
type Customer (id, name) =
do // Constructor
if id <= 0 then
raise(new ArgumentException("Invalid ID.", "id"))
elif String.IsNullOrEmpty(name) then
raise(new ArgumentException("Invalid Name.", "name"))
member this.ID
with get() = id
member this.Name
with get() = name
member this.ModifyName value =
new Customer(id, value)
Mutable Version
type Customer (id) =
let mutable name = ""
do // Constructor
if id <= 0 then
raise(new ArgumentException("Invalid ID.", "id"))
member this.ID
with get() = id
member this.Name
with get() = name
and set value =
if String.IsNullOrEmpty(name) then
raise(new ArgumentException("Invalid Name.", "value"))
name <- value
Have you taken a look at my FunctionalNHibernate project? It's designed as a layer on top of nhibernate to let you declaratively map records to a database. It's early days, but it's just about usable:
http://bitbucket.org/robertpi/functionalnhibernate/

Entity Framework - Select specific columns and return strongly typed without losing cast

I'm trying to do something similar to this post where I don't pull back all columns from a particular entity, however my framework makes use of inheritence and I lose scope of the entity type after it's been cast to an anonymous type.
The structure of my Entity Framework has a base entity called Action. From here I've created two inherited entities called Event and Activity. I want to pull back the last X Actions and pass them to my strongly typed view which accepts an Action and from there determines if its an Activity or Event and renders the correct partial view.
if(Model.GetType() == typeof(Event))
{
//render Event view
}
else if(Model.GetType() == typeof(Activity))
{
//render Activity view
}
I can pull the last 10 as an anonymous type and then cast:
var result = from a in new DataContext().Actions
where a.UserId == someGuidValue
select new { a.CreatedOn, a.Summary };
List<Action> list = result.AsEnumerable()
.Select(o => new Action {
CreatedOn = o.CreatedOn,
Summary = o.Summary
}).ToList();
However, once I pass the new List of Actions to my strongly typed view it loses scope of whether it's an Activity or an Event since it's been cast as an Action. My question is, without exposing the discriminator column, is there any way to cast each item to the proper type or am I going about this the wrong way?
A bit kludgy, but will work:
var result = from a in new DataContext().Actions
where a.UserId == someGuidValue
let IsEvent = a as Event != null
select new { a.CreatedOn, IsEvent, a.Summary };
List<Action> list = result.AsEnumerable()
.Select(o => o.IsEvent ?
(Action) new Event {
CreatedOn = o.CreatedOn,
Summary = o.Summary
}
: (Action) new Activity {
CreatedOn = o.CreatedOn,
Summary = o.Summary
}
}).ToList();
Example with type-specific columns, presuming that e.EventSpecific is of a nullable type.
var result = from a in new DataContext().Actions
where a.UserId == someGuidValue
let ev = a as Event
let IsEvent = ev != null
select new { a.CreatedOn, IsEvent, a.Summary, ev.EventSpecific };
List<Action> list = result.AsEnumerable()
.Select(o => o.IsEvent ?
(Action) new Event {
CreatedOn = o.CreatedOn,
Summary = o.Summary,
EventSpecific = o.EventSpecific
}
: (Action) new Activity {
CreatedOn = o.CreatedOn,
Summary = o.Summary,
EventSpecific = o.EventSpecific // will be null, but using o.EventSpecific saves casting
}
}).ToList();
If o.EventSpecific is of a non-nullable type, then you must convert it to a nullable type in the L2E query.
You are probably on the wrong way. At first I would assume that Action should be an abstract class and you should not be able to create instances of it at all. If you then only fetch a subset of the properties and the subset does no longer allow to discriminate between events and activities, it is probably the wrong way to try making events and activities out of them.
So it actually seems not to be a technical problem - it should be quite easy to include some discrimination information in the anonymous type - but a design problem. I suggest to rethink if it is required to discriminate the query result and if so if it is really a good idea to discriminate the result in absence of an discriminator.

Resources