Pass a closure capturing constructor argument to base class constructor - f#

I want to derive a class from System.IO.BinaryWriter, and call it's constructor with a custom Stream, an implementation of which captures a constructor argument of the derived type. For the life of me, I cannot figure out whether even this is possible at all. What I am essentially trying to do, slightly trimmed to be an MCV, is
type HashingBinaryWriter private
(hasher : System.Security.Cryptography.HashAlgorithm,
stream : System.IO.Stream) =
inherit System.IO.BinaryWriter(stream)
let unsupp() = raise(System.NotSupportedException())
let hash_stream =
{ new System.IO.Stream() with
member __.CanRead = false
member __.CanSeek = false
member __.CanWrite = true
member __.Length = unsupp()
member __.Position with get() = unsupp() and set(_) = unsupp()
member __.Seek(_,_) = unsupp()
member __.SetLength _ = unsupp()
member __.Read(_,_,_) = unsupp()
member __.Flush() = ()
member __.Write(buffer, offset, count) =
hasher.TransformBlock(buffer, offset, count, null, 0) |> ignore
}
new(hasher) = new HashingBinaryWriter(hasher, hash_stream)
// Or, alternatively
new(hasher) as me = new HashingBinaryWriter(hasher, me.hash_stream)
The last line fails to compile because hash_stream is undefined, in either form. Apparently, as this answer suggests, the scope of constructor arguments is different from that of class declaration body, but I need to understand what is going on here (and if possible the why behind the F# design decision).
Indeed, I can see some workarounds (convert hash_stream to a private property, for example), but my vocabulary of F# idioms is lacking this one. My second question is, then, what would be the idiomatic way of doing this.

There are multiple ways to do this - and I guess the right choice depends on how your complete implementation will look.
If you wanted something that is as close to the version in your question as possible, then you can just move unsupp and hash_stream inside the constructor:
type HashingBinaryWriter private
(hasher : System.Security.Cryptography.HashAlgorithm,
stream : System.IO.Stream) =
inherit System.IO.BinaryWriter(stream)
new(hasher : System.Security.Cryptography.HashAlgorithm) =
let unsupp() = raise(System.NotSupportedException())
let hash_stream =
{ new System.IO.Stream() with
member __.CanRead = false
member __.CanSeek = false
member __.CanWrite = true
member __.Length = unsupp()
member __.Position with get() = unsupp() and set(_) = unsupp()
member __.Seek(_,_) = unsupp()
member __.SetLength _ = unsupp()
member __.Read(_,_,_) = unsupp()
member __.Flush() = ()
member __.Write(buffer, offset, count) =
hasher.TransformBlock(buffer, offset, count, null, 0) |> ignore
}
new HashingBinaryWriter(hasher, hash_stream)
I guess that this can easily get ugly if your implementation of hash_stream gets longer. In that case, it would make more sense to do what John suggests in the comments and move the implementation of the stream outside of the class, perhaps into a helper module:
let unsupp() = raise(System.NotSupportedException())
let createHashStream (hasher : System.Security.Cryptography.HashAlgorithm) =
{ new System.IO.Stream() with
member __.CanRead = false
member __.CanSeek = false
member __.CanWrite = true
member __.Length = unsupp()
member __.Position with get() = unsupp() and set(_) = unsupp()
member __.Seek(_,_) = unsupp()
member __.SetLength _ = unsupp()
member __.Read(_,_,_) = unsupp()
member __.Flush() = ()
member __.Write(buffer, offset, count) =
hasher.TransformBlock(buffer, offset, count, null, 0) |> ignore
}
type HashingBinaryWriter private
(hasher : System.Security.Cryptography.HashAlgorithm,
stream : System.IO.Stream) =
inherit System.IO.BinaryWriter(stream)
new(hasher : System.Security.Cryptography.HashAlgorithm) =
new HashingBinaryWriter(hasher, createHashStream hasher)

Related

Circular reference and constructors

I'm trying to build an Attribute that validates a certain instance of a type.
In order to do this I have to cast the ObjectInstance to that type.
And I need to set the attribute on the member of that type.
So we need to resort to the and keyword for the circular definition.
However in the following case I get the error that
A custom attribute must invoke an object constructor
On the line marked below.
namespace Test
open System
open System.ComponentModel.DataAnnotations
[<AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)>]
type MyAttribute() =
class
inherit ValidationAttribute ()
override this.IsValid (value: Object, validationContext: ValidationContext) =
match validationContext.ObjectInstance with
| :? MyClass as item ->
// TODO more validation
ValidationResult.Success
| _ ->
new ValidationResult("No no no")
end
and MyClass(someValue) =
[<Required>]
[<Range(1, 7)>]
//vvvvvvvvvvvvvvv
[<MyAttribute>]
//^^^^^^^^^^^^^^^
member this.SomeValue : int = someValue
I tried manually invoking the constructor, such as:
[<MyAttribute()>]
// or
[<new MyAttribute()>]
But none of them are accepted by the system.
Can an F# guru help me out here?
Interesting one. It seems that the type inference is really not getting that right. The correct syntax to use here is [<MyAttribute()>], but despite you using the and keyword, the MyAttribute class is not yet known.
Here is a workaround: First check that the object to validate is really of the right type, then use reflection to invoke a validation method:
[<AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)>]
type MyAttribute() =
inherit ValidationAttribute ()
override this.IsValid (value: Object, validationContext: ValidationContext) =
let t = validationContext.ObjectInstance.GetType()
if t.FullName = "Test.MyClass" then
let p = t.GetMethod("IsValid")
if p.Invoke(validationContext.ObjectInstance, [| |]) |> unbox<bool> then
ValidationResult.Success
else
ValidationResult("failed")
else
new ValidationResult("No no no")
type MyClass(someValue: int) =
[<Required>]
[<Range(1, 7)>]
[<MyAttribute()>]
member this.SomeValue = someValue
member this.IsValid() = someValue <= 7
Edit: to make that slightly cleaner, you could add an interface, that you use in your validation attribute, and later implement in your class.
type IIsValid =
abstract member IsValid: unit -> bool
Your IsValid method then becomes
override this.IsValid (value: Object, validationContext: ValidationContext) =
match validationContext.ObjectInstance with
| :? IIsValid as i ->
if i.IsValid() then
ValidationResult.Success
else
ValidationResult("failed")
| _ ->
ValidationResult("No no no")
in your class, this looks like:
type MyClass(someValue: int) =
[<Required>]
[<Range(1, 7)>]
[<MyAttribute()>]
member this.SomeValue = someValue
interface IIsValid with
member this.IsValid() = someValue <= 7
One solution would be to first describe your types in a signature files.
Since the attribute is specified in the signature file, you don't need to add it again in the implementation file:
Foo.fsi:
namespace Foo
open System
[<AttributeUsage(AttributeTargets.Property)>]
type MyAttribute =
inherit System.Attribute
new : unit -> MyAttribute
member Foo : unit -> MyClass
and MyClass =
new : someValue : int -> MyClass
[<MyAttribute()>]
member SomeValue : int
Foo.fs:
namespace Foo
open System
[<AttributeUsage(AttributeTargets.Property)>]
type MyAttribute() =
inherit Attribute()
member this.Foo () =
new MyClass(1)
and MyClass(someValue) =
// [<MyAttribute()>] -> specified in the fsi, still appears in compiled code
member this.SomeValue : int = someValue
See https://msdn.microsoft.com/en-us/library/dd233196.aspx for reference
One thing that you can do to get rid of mutual recursion is to break up MyClass definition into two and use type augmentation to add the members you want to mark with the attribute.
type MyClass(someValue: int) =
member internal this.InternalSomeValue = someValue
type MyAttribute() =
inherit ValidationAttribute()
(* you can refer to MyClass here *)
type MyClass with
[<MyAttribute()>]
member this.SomeValue = this.InternalSomeValue
That's closer to what you're asking for, but I like the interface idea better.

F# how to deal with this recursive mutal class method

I have the following piece of code where I need to call on my own class that I reference via a reference on a mutual class(hope that makes sense, if not the code sample explains it better).
Unfortunately it does work because I get the "Lookup on object of indeterminate type prior to..." error on the 'x.Connections.[0].Dest.Func' part.
Can anyone think of a way to fix this, possibly I will have to just go for quite a different approach?
type Node() =
member x.Connections = new System.Collections.Generic.List<Connection>()
member x.Connect other = x.Connections.Add(Connection(x, other))
member x.Func i : unit = x.Connections.[0].Dest.Func i
and Connection(source : Node, dest : Node) =
member val Source = source
member val Dest = dest
Ignore the fact that calling the Func method on Node serves no purpose, I've simplified this from the real code to try to just show what causes the problem.
Thanks in advance.
You can also just add a type annotation to Dest, which appears to be the critical symbol that throws the type inference algorithm into a loop:
type Node() =
member x.Connections = new System.Collections.Generic.List<Connection>()
member x.Connect other = x.Connections.Add(Connection(x, other))
member x.Func i : unit = x.Connections.[0].Dest.Func i
and Connection(source : Node, dest : Node) =
member val Source = source
member val Dest : Node = dest
Try declaring that method at the end:
type Node() =
member x.Connections = new System.Collections.Generic.List<Connection>()
member x.Connect other = x.Connections.Add(Connection(x, other))
and Connection(source : Node, dest : Node) =
member val Source = source
member val Dest = dest
type Node with
member x.Func i : unit = x.Connections.[0].Dest.Func i
or may be better swap the order of the types:
type Connection(source : Node, dest : Node) =
member val Source = source
member val Dest = dest
and Node() =
member x.Connections = new System.Collections.Generic.List<Connection>()
member x.Connect other = x.Connections.Add(Connection(x, other))
member x.Func i : unit = x.Connections.[0].Dest.Func i

Custom IEnumerator in F#

More F# questions. I have the implementation of a binary reader below. I want it to work like an enumerable sequence. The code below gives me the following error and I have as usual no clue how to resolve it. I have a c# implementation where I had to implement two different overrides for .Current property. I guess I have to do the same here but not sure how. As always, thanks a million in advance for your help.
error FS0366: No implementation was given for Collections.IEnumerator.get_Current() : obj. Note that all interface members must be implemented and listed under an appropriate interface declaration, e.g. interface ... with member ....
namespace persisitence
open System.Collections.Generic
open System
open System.IO
type BinaryPersistenceIn<'T>(fn: string, serializer: ('T * BinaryReader) -> unit) as this =
let stream_ = File.Open(fn, FileMode.Open, FileAccess.Read)
let reader_ = new BinaryReader(stream_)
[<DefaultValue>] val mutable current_ : 'T
let eof() =
stream_.Position = stream_.Length
interface IEnumerator<'T> with
member this.MoveNext() =
let mutable ret = eof()
if stream_.CanRead && ret then
serializer(this.current_, reader_)
ret
member this.Current
with get() = this.current_
member this.Dispose() =
stream_.Close()
reader_.Close()
member this.Reset() =
stream_.Seek((int64) 0., SeekOrigin.Begin) |> ignore
As #Richard pointed out, you need to implement IEnumerator.Current.
Here's code in response to your question "how to do it". This should work:
A few notes: (thanks to #DaxFohl)
IEnumerator is in different namespace (see code).
MoveNext and Reset are really members of IEnumerator, not IEnumerator<'t>, so that's where they should be implemented.
Dispose, however, is on IEnumerator<'t> (surprise! :-)
-
type BinaryPersistenceIn<'T>(fn: string, serializer: ('T * BinaryReader) -> unit) as this =
...
interface IEnumerator<'T> with
...
member this.Current
with get() = this.current_
interface System.Collections.IEnumerator with
member this.Current
with get() = this.current_ :> obj
member this.MoveNext() = ...
member this.Reset() = ...
And in conclusion, I must add this: are you really sure you want to implement IEnumerator? This is a rather low-lever thing, easy to get wrong. Why not use a sequence computation expression instead?
let binaryPersistenceSeq (fn: string) (serializer: BinaryReader -> 'T) =
seq {
use stream_ = File.Open(fn, FileMode.Open, FileAccess.Read)
use reader_ = new BinaryReader(stream_)
let eof() = stream_.Position = stream_.Length
while not eof() do
if stream_.CanRead then
yield serializer reader_
}
IEnumerator<T> extends IEnumerator and IEnumerator has a Current property of type object.
You need to also implement IEnumerator.Current separately from IEnumerator<T>.Current.
This version of the code compiles... as to does it really work.. will find out.
type BinaryPersistenceIn<'T>(fn: string, serializer: ('T * BinaryReader) -> unit) =
let stream_ = File.Open(fn, FileMode.Open, FileAccess.Read)
let reader_ = new BinaryReader(stream_)
[<DefaultValue>] val mutable current_ : 'T
let eof() =
stream_.Position = stream_.Length
interface IEnumerator<'T> with
member this.MoveNext() =
let mutable ret = eof()
if stream_.CanRead && ret then
serializer(this.current_, reader_)
ret
member this.Current
with get() = this.current_
member this.Dispose() =
stream_.Close()
reader_.Close()
member this.Reset() =
stream_.Seek((int64) 0., SeekOrigin.Begin) |> ignore
member this.Current
with get() = this.current_ :> obj

Is it possible for an object to access private field / function of another object of same class?

I know this is possible in C#, which produces simple and efficient code. --- Two objects of the same class can access each other's private parts.
class c1
{
private int A;
public void test(c1 c)
{
c.A = 5;
}
}
But It seems impossible in F#, is it true?
type c1()
let A = 0
member test (c: c1) = c.A
Interesting question. It seems to work with an explicit field but not with a let binding:
// Works
type c1 =
val private A : int
new(a) = { A = a }
member m.test(c : c1) = c.A
let someC1 = new c1(1)
let someMoreC1 = new c1(42);
let theAnswer = someC1.test someMoreC1
// Doesn't work
type c2() =
let mutable A = 42
// Compiler error: The field, constructor or member 'A' is not defined
member m.test(c : c2) = c.A
Yes, but in your example A is not semantically a private member of c1, it is more like a local variable of the constructor.
#afrischke gives an example of how to define c1 with an actual private member A (using val fields).
As section 8.6.1.3 of the F# spec states:
The functions and values defined by instance definitions are lexically scoped (and thus implicitly private) to the object being defined.
This is possible and it is widely used, for example, for checking memberwise equality:
type c1 =
member private this.A = 0
interface IEquatable<c1> with
member this.Equals (that: c1) = this.A = that.A
// of course, it can be done in a regular method as well
member this.Equals (that: c1) = this.A = that.A
You just use a directly in an instance method
type c1()
let A = 0
member x.test = A
For a static method this doesn't work as let bindings are slightly different - then you need a class definition like
type c1()
private member x.A = 0
static member test (A:c1) = A.A

member list ref not updating

After a hiatus from my Silverlight / F# application, i am starting back into it and am running into an issue I cannot seem to get my head around. I have a member variable of my usercontrol that is a list ref, on button clicks I want to add records to it - but it never updates. I am pretty sure it has to do with being a member but I havent figured it out.
Thanks in advance to those who take the time to view and reply.
the problem lines:
.
.
.
member this.brokers = ref List.empty
.
.
.
// this line doesn't seem to work
this.brokers := candidate :: (!this.brokers)
.
.
.
the class:
type Page() as this =
inherit UriUserControl("/xyz;component/page.xaml", "page")
do
this.firm.ItemsSource <- RpcXYZ.getFirms()
this.email.Background <- SolidColorBrush(Colors.Red)
this.addBtn.IsEnabled <- false
()
// instance data
member this.brokers = ref List.empty
// bound controls for add candidate
member this.FE : FrameworkElement = (this.Content :?> FrameworkElement)
member this.fname : TextBox = this.FE ? fname
member this.lname : TextBox = this.FE ? lname
member this.email : TextBox = this.FE ? email
member this.firm : RadComboBox = this.FE ? firms
member this.addBtn : RadButton = this.FE ? addBtn
member this.addCadidate_Click (sender : obj) (args : RoutedEventArgs) =
let inline findFirm (f : RpcXYZ.firm) =
f.id = Int32.Parse(this.firm.SelectedValue.ToString())
let candidate : SalesRep = {
id = -1 ;
fname = this.fname.Text ;
lname = this.lname.Text ;
email = this.email.Text ;
phone = "" ;
firm = List.find findFirm <| RpcXYZ.getFirms();
score = None ;
}
// this line is fine t is a list of 1 item after 1 click
let t = candidate :: (!this.brokers)
// this line doesn't seem to work
this.brokers := candidate :: (!this.brokers)
ChildWindow().Show() |> ignore ;
member this.email_Changed (o : obj) (arg : TextChangedEventArgs) =
let txtBox = (o :?> TextBox)
let emailRegex = Regex("(\w[-._\w]*\w#\w[-._\w]*\w\.\w{2,3})")
if emailRegex.IsMatch(txtBox.Text) = false then
txtBox.Background <- SolidColorBrush(Colors.Red)
this.addBtn.IsEnabled <- false
else
txtBox.Background <- new SolidColorBrush(Colors.White)
this.addBtn.IsEnabled <- true
This
member this.brokers = ref List.Empty
defines a property getter. Every time you touch .brokers, it re-runs the code on the right hand side. That's the issue.
The fix would be to define an instance variable, and return that:
let brokers = ref List.Empty
member this.Brokers = brokers
Then a single ref is allocated when an instance of the class is constructed, and you keep accessing that same ref object via the member property.
Brian already explained the problem. However, is there any reason why you're not using a mutable member (with getter and setter) and instead use a readonly member that returns a reference cell?
Using a get/set member would be more idiomatic solution:
let mutable brokers = List.Empty
member this.Brokers
with get() = brokers
and set(value) = brokers <- value
The declaration is a bit longer (unfortunately, there are no automatic properties in F#!), but the member will look like a standard property (from both F# and C#). You could then use it like this:
x.Brokers <- candidate :: x.Brokers
Although, you need the property only for public members that should be accessed from outside of the type. For private fields, you can just use the mutable value brokers directly...

Resources