tag:blogger.com,1999:blog-12651253317652051732024-03-18T10:17:54.524+01:00Dreamstate CodingUnknownnoreply@blogger.comBlogger87125tag:blogger.com,1999:blog-1265125331765205173.post-85370811781411600242020-09-13T01:30:00.003+02:002020-09-13T01:33:19.269+02:00Orbital velocity and altitude calculations in C#<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjh7NtCPcntNzPSpZXUHZtAnlfKkAjN04eMNJ-XcONNCkGKGVPK6ZJJLM1RAruGWHpJ8C_DMubOBOzRPCZgU44ZzFRrBGR_UsMJ6lH_6wqtqvYhVv8dAXACTvOYA2yQp87mLEWZMqJSGyM/s750/Orbital+velocity+and+altitude+calculations+in+C%2523.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="289" data-original-width="750" height="241" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjh7NtCPcntNzPSpZXUHZtAnlfKkAjN04eMNJ-XcONNCkGKGVPK6ZJJLM1RAruGWHpJ8C_DMubOBOzRPCZgU44ZzFRrBGR_UsMJ6lH_6wqtqvYhVv8dAXACTvOYA2yQp87mLEWZMqJSGyM/w625-h241/Orbital+velocity+and+altitude+calculations+in+C%2523.jpg" width="625" /></a></div><p>Just thought I'd share a C# snippet for calculating nominal orbital speed if you have the center mass and orbital radius. And to go the other way if you have the center mass and speed to get the nominal orbital radius.</p>
<br />
<pre>public static class OrbitalCalculations
{
public const double G = 0.0000000000667d;
public static double NominalOrbitalSpeed(double centerMass, double orbitalRadius)
{
if (orbitalRadius.IsZero())
return 0;
return Math.Sqrt(G * centerMass / orbitalRadius);
}
public static double NominalOrbitalRadius(double centerMass, double speed)
{
if (speed.IsZero())
return 0;
return G * centerMass / (speed * speed);
}
public static bool IsZero(this double d, double tolerance = 0.0001)
{
return Math.Abs(d) < tolerance;
}
}
</pre>
If you want the math behind and more: <div><ul style="text-align: left;"><li><a href="https://www.softschools.com/formulas/physics/orbital_velocity_formula/76/" target="_blank">softschools.com: Orbital Velocity Formula</a></li></ul><div><br /></div></div><div>Hope this helps someone out there! : )</div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1265125331765205173.post-34101400459172859752020-03-19T16:27:00.000+01:002020-03-19T19:07:14.701+01:00A TwoWay or OneWayToSource binding cannot work on the read-only propertyI ran into an InvalidOperationException when binding to a read-only property in the model<br />
<br />
I.e. my model looks something like this:<br />
<pre>public class Customer
{
public Guid Id { get; set; }
public string Name { get; set; }
public List<order> Orders { get; set; }
public double CalculatedProperty => Orders.Sum(x => x.TotalPrice);
}</order></pre>
And my binding in XAML something like:<br />
<pre>{Binding CalculatedProperty, StringFormat='0.00'}</pre>
<br />
To get around this, we need to update the binding to set the Mode to something else then TwoWay or OneWayToSource, simplest is to just set it to OneWay like the following:<br />
<pre>{Binding CalculatedProperty, StringFormat='0.00', Mode=OneWay}</pre>
<br />
<br />
<br />
Hope this helps someone out there!<br />
<br />
Full exceptioon stack-trace<br />
<pre>System.InvalidOperationException
HResult=0x80131509
Message=A TwoWay or OneWayToSource binding cannot work on the read-only property 'CalculatedProperty' of type 'Model.Entity.Customer'.
Source=PresentationFramework
StackTrace:
at MS.Internal.Data.PropertyPathWorker.CheckReadOnly(Object item, Object info)
at MS.Internal.Data.PropertyPathWorker.ReplaceItem(Int32 k, Object newO, Object parent)
at MS.Internal.Data.PropertyPathWorker.UpdateSourceValueState(Int32 k, ICollectionView collectionView, Object newValue, Boolean isASubPropertyChange)
at MS.Internal.Data.ClrBindingWorker.AttachDataItem()
at System.Windows.Data.BindingExpression.Activate(Object item)
at System.Windows.Data.BindingExpression.AttachToContext(AttachAttempt attempt)
at System.Windows.Data.BindingExpression.MS.Internal.Data.IDataBindEngineClient.AttachToContext(Boolean lastChance)
at MS.Internal.Data.DataBindEngine.Task.Run(Boolean lastChance)
at MS.Internal.Data.DataBindEngine.Run(Object arg)
at MS.Internal.Data.DataBindEngine.OnLayoutUpdated(Object sender, EventArgs e)
at System.Windows.ContextLayoutManager.fireLayoutUpdateEvent()
at System.Windows.ContextLayoutManager.UpdateLayout()
at System.Windows.ContextLayoutManager.UpdateLayoutCallback(Object arg)
at System.Windows.Media.MediaContext.InvokeOnRenderCallback.DoWork()
at System.Windows.Media.MediaContext.FireInvokeOnRenderCallbacks()
at System.Windows.Media.MediaContext.RenderMessageHandlerCore(Object resizedCompositionTarget)
at System.Windows.Media.MediaContext.RenderMessageHandler(Object resizedCompositionTarget)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.DispatcherOperation.InvokeImpl()
at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)
at MS.Internal.CulturePreservingExecutionContext.CallbackWrapper(Object obj)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at MS.Internal.CulturePreservingExecutionContext.Run(CulturePreservingExecutionContext executionContext, ContextCallback callback, Object state)
at System.Windows.Threading.DispatcherOperation.Invoke()
at System.Windows.Threading.Dispatcher.ProcessQueue()
at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
at System.Windows.Threading.Dispatcher.Run()
at System.Windows.Application.RunDispatcher(Object ignore)
at System.Windows.Application.RunInternal(Window window)
at System.Windows.Application.Run()
at UI.WPF.App.Main()
This exception was originally thrown at this call stack:
MS.Internal.Data.PropertyPathWorker.CheckReadOnly(object, object)
MS.Internal.Data.PropertyPathWorker.ReplaceItem(int, object, object)
MS.Internal.Data.PropertyPathWorker.UpdateSourceValueState(int, System.ComponentModel.ICollectionView, object, bool)
MS.Internal.Data.ClrBindingWorker.AttachDataItem()
System.Windows.Data.BindingExpression.Activate(object)
System.Windows.Data.BindingExpression.AttachToContext(System.Windows.Data.BindingExpression.AttachAttempt)
System.Windows.Data.BindingExpression.MS.Internal.Data.IDataBindEngineClient.AttachToContext(bool)
MS.Internal.Data.DataBindEngine.Task.Run(bool)
MS.Internal.Data.DataBindEngine.Run(object)
MS.Internal.Data.DataBindEngine.OnLayoutUpdated(object, System.EventArgs)
...
[Call Stack Truncated]
</pre>
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1265125331765205173.post-21867768387120326052020-02-24T11:32:00.001+01:002020-02-24T11:36:19.588+01:00Cancer and Chemotherapy<div class="separator" style="clear: both; text-align: center;">
<a href="https://dreamstateadventures.blogspot.com/2020/02/cancer-and-chemotherapy.html"><img border="0" data-original-height="375" data-original-width="749" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjojrHeP8Ezg7pQ4T2ICM-pg6yt2WPr_dzXwzq7Yuw2wY4cRWFhIlE2TqcijuQB0i2fQUw1GOk7CvYzd-dGVj7x1sm6JfL9fDBwuZA-wiRSKwLPCXGOpyNJXC-zuXclO7LCGwJN6cJDtxs/s1600/cancer+and+chemotherapy.jpg" /></a></div>
<br />
I thought that I'd cross-post this here for information. <a href="https://dreamstateadventures.blogspot.com/2020/02/cancer-and-chemotherapy.html">The full post is available here</a>.<br />
<br />
They found something blocking my bile duct that they think is cancer. After battling acute pancreatitis in the autumn I was to undergo a Whipple surgery in January, during which they found that they can't do that. As the tumor i too locally advanced, meaning that it has grown in to stuff in my case one of the main veins and arteries going to the liver.<br />
<br />
<div style="text-align: center;">
</div>
<br />
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: "Times New Roman"; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; letter-spacing: normal; margin: 0px; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;">
So I am back on chemotherapy after a year without. I decided to start a <a href="https://www.youtube.com/playlist?list=PL6eTnitji9xgq7uEC4U9f5PTfsPo8e_4p" target="_blank">VLOG on YouTube</a> about it if you are interested in following me on the journey. If not, up to you. : )</div>
<div style="text-align: center;">
<iframe allowfullscreen="" frameborder="0" gesture="media" height="315" src="https://www.youtube.com/embed/XAj6OaQWi2U" width="560"></iframe>
</div>
Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-1265125331765205173.post-67947223760109837732019-03-20T19:09:00.002+01:002019-03-20T19:09:32.845+01:00MonoGame: Static Camera Tutorial and code<div class="separator" style="clear: both; text-align: center;">
<img border="0" data-original-height="405" data-original-width="749" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLfCmDq4Qtq2UmZS_KFcYyO_JD8S96aP3GgGxqwnb8yJJUC_3Mps0taAoXgVkKfisFh6ml2MKmqKXdNKWFQF39nc4tBPy7bmn_WPuRpfjlBZuTppLlDB6O8M7n_vgOAhlxjL045pzp8X0/s1600/MonoGame+Static+Camera+Tutorial+and+code.jpg" /></div>
<br />
Some of you may have noticed my series on <a href="https://dreamstatecoding.blogspot.com/p/opengl4-with-opentk-tutorials.html">openGL with openTK in C#</a> that I wrote some years ago. Since then my life has been quite full of stuff happening so I never got around to look at lightning or other stuff to make sure that I would end up with a working engine.<br />
<br />
Lately I found MonoGame and started to experiment with it, turns out that it has much of the stuff that I want to use so I ended up writing some stuff with it.<br />
<br />
Here I thought that I would share a basic static camera class and its usage as it took some time for me to understand how to get it working together with the BasicEffect class provided by MonoGame.<br />
<br />
Some code. Let's start to look at the interface that we would want to use with out cameras.<br />
<br />
<pre>public interface ICamera
{
Matrix ViewMatrix { get; }
Matrix ProjectionMatrix { get; }
void Update(GameTime gameTime);
}
</pre>
<br />
We want our cameras to expose their View and Projection matrices as they will be used to integrate the camera with MonoGame BasicEffect.<br />
Also, as we will be using this interface with all of our cameras we may want to update it in each frame, hence the Update(GameTime gametTime) method. GameTime is provided by MonoGame and contains two timespans, time since game start and time since last frame.<br />
<br />
<br />
Next we look at the actual StaticCamera, a camera that once created will remain static in the world. I.e. you place it at a position and point it towards something interesting and it will look at that position until you remove the camera. Useful for some scenarios and a good stepping point for creating more advanced camera classes.<br />
<br />
We want our camera to have a Position in in the game world and a Direction.<br />
<br />
<pre>using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
public class StaticCamera : ICamera
{
public Vector3 Position { get; }
public float FieldOfView { get; }
public float NearPlane { get; }
public float FarPlane { get; }
public Vector3 Direction { get; }
public Matrix ViewMatrix { get; }
public Matrix ProjectionMatrix { get; }
public StaticCamera(GraphicsDevice graphicsDevice, float fieldOfViewDegrees, float nearPlane, float farPlane)
: this(graphicsDevice, fieldOfViewDegrees, nearPlane, farPlane, Vector3.Zero, -Vector3.UnitZ)
{ }
public StaticCamera(GraphicsDevice graphicsDevice, float fieldOfViewDegrees, float nearPlane, float farPlane, Vector3 position, Vector3 target)
{
FieldOfView = fieldOfViewDegrees * 0.0174532925f;
Position = position;
Direction = Vector3.Normalize(target - position);
ViewMatrix = Matrix.CreateLookAt(Position, Direction, Vector3.Up);
ProjectionMatrix = Matrix.CreatePerspectiveFieldOfView(
FieldOfView,
graphicsDevice.Viewport.AspectRatio,
nearPlane,
farPlane);
}
public void Update(GameTime gameTime)
{ }
}
</pre>
<br />
We have two constructors, the first one takes a GraphicsDevice reference that we need to figure out what resolution and especially what aspect ration our current view port has. (i.e. screen resolution/window size)<br />
Also, we want to specify the lense angle in degrees. I.e. 60 degree lense.<br />
The near and far clipping planes, i.e. we will only want to render objects that are between those two distances from the camera.<br />
The first constructor creates a camera located at coordinates (0, 0, 0) looking inward (0, -1, 0)<br />
<br />
The second constructor takes also the position and target to look at.<br />
We calculate the radians of the camera lense by multiplying the field of view degrees with 0.01745...<br />
After that we figure out the direction that the camera points at by subtracting the camera location from the target and normalizing the result.<br />
<br />
To get the ViewMatrix we use the Matrix.CreateLookAt function that takes Position, Direction and an up vector<br />
To get the ProjectionMatrix we use the Matrix.CreatePerspectiveFieldOfView function that takes the field of view, aspect ration and near/far planes.<br />
This is pretty much all for a simple static camera using the MonoGame framework.<br />
<br />
Next step is to use the camera.<br />
<br />
<pre>private ICamera _camera;
protected override void LoadContent()
{
_camera = new StaticCamera(GraphicsDevice, 60, 1, 200, new Vector3(1, -10, 0), Vector3.Zero);
}
</pre>
<br />
I put the above code in my Game1.cs file. As the default Game1 class inherits from Game, it will have GraphicsDevice provided and we just need to send it into the constructor together with field of view angle, near and far planes, position and target coordinates to look at.<br />
<br />
All of my game objects inherit from the following abstract GameObject class<br />
<pre>public abstract class AGameObject
{
public Vector3 Coordinates;
public Vector3 Rotation;
public Vector3 Velocity;
public float Scale = 1f;
}
</pre>
So each game object has a position in the game world that is stored in Coordinates, it also has an rotation, velocity and scale.<br />
<br />
<br />
Whenever we want to render a game object in a scene, we wrap it in a Renderable object that also has a model and a Draw method:<br />
<pre>public class Renderable
{
public VertexPositionNormalTexture[] Model;
public BasicEffect BasicEffect;
public AGameObject GameObject;
public Renderable(AGameObject gameObject, GraphicsDevice graphicsDevice)
{
GameObject = gameObject;
BasicEffect = new BasicEffect(graphicsDevice)
{
AmbientLightColor = Vector3.One,
LightingEnabled = true,
DiffuseColor = Vector3.One,
};
}
public void Draw(GraphicsDevice graphicsDevice, ICamera camera)
{
var t2 = Matrix.CreateTranslation(GameObject.Coordinates.X, GameObject.Coordinates.Y, GameObject.Coordinates.Z);
var r1 = Matrix.CreateRotationX(GameObject.Rotation.X);
var r2 = Matrix.CreateRotationY(GameObject.Rotation.Y);
var r3 = Matrix.CreateRotationZ(GameObject.Rotation.Z);
var s = Matrix.CreateScale(GameObject.Scale);
BasicEffect.World = r1 * r2 * r3 * s * t2;
BasicEffect.View = camera.ViewMatrix;
BasicEffect.Projection = camera.ProjectionMatrix;
BasicEffect.EnableDefaultLighting();
foreach (var pass in BasicEffect.CurrentTechnique.Passes)
{
pass.Apply();
graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, Model, 0, Model.Length / 3);
}
}
}
</pre>
<br />
Here we can see that the render method takes a graphicsDevice and camera. Here we take the ViewMatrix from the camera and put it in the BasicEffect.View, and the same goes for the ProjectionMatrix that is put in BasicEffect.Projection.<br />
The BasicEffect.World receives the rotated, scaled and translated matrix generated from the GameObject.<br />
<br />
Now we need to look up our Draw method in the main game file (Game1.cs) and place calls to render our Renderables there<br />
<pre>private List<Renderable> _scene = new List<Renderable>();
private readonly RasterizerState _rasterizerState = new RasterizerState
{
CullMode = CullMode.CullClockwiseFace
};
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.RasterizerState = _rasterizerState;
GraphicsDevice.Clear(Color.CornflowerBlue);
foreach(var x in _scene)
{
x.Draw(GraphicsDevice, _camera);
}
base.Draw(gameTime);
}
</pre>
First we tell the graphics device to save some time by culling triangles that are backwards facing, we then clear the scene to a background color.<br />
For simplicity we store all our Renderables in a list called _scene and iterate through it and call Draw on each element.<br />
<br />
<br />
I hope this helps someone out there to get unstuck when starting to use MonoGame.<br />
<br />
<i>All code provided as-is. This is copied from my own code-base, May need some additional programming to work. Use for whatever you want, how you want! If you find this helpful, please leave a comment or share on social media, not required but much appreciated! :)</i>Unknownnoreply@blogger.com3tag:blogger.com,1999:blog-1265125331765205173.post-92016974829152657602018-12-08T16:25:00.001+01:002018-12-08T16:25:47.498+01:00F# typed tuples and how to pattern match them<div class="separator" style="clear: both; text-align: center;">
<img border="0" data-original-height="392" data-original-width="750" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwUz_hlSczxZCy9y_vNYo-4szGxmxBSnMvJ2ffIrg3-QOvCDOq1x4SfxFgbYvj3pG8FxnrzspQyEPqYTarT9fW2l9yF7efJ8rovouKS8MMSwug4yUksiDhqQTeBdVlxKnAbdlNRSGip9I/s1600/F%2523+typed+tuples+and+how+to+pattern+match+them.jpg" /></div>
<br />
Noticed a warning fly-by in the compiler log in Visual Studio<br />
<pre>warning FS0026: This rule will never be matched</pre>
<br />
When I opened the location that it complained about I saw the following code from my main event reducer:<br />
<pre>let HandleEvent (state:State) (event:ApplicationEvent) : State =
match event with
| ApplicationEvent (h, p) ->
{
CurrentPlayer = CurrentPlayerReducer.HandleEvent state h p
LastEventId = Some h.Id
Timestamp = h.Timestamp
PlayerStore = PlayerReducer.HandleEvent state.PlayerStore h p
SpaceBodyStore = SpaceBodyReducer.HandleEvent state.SpaceBodyStore h p
}
| _ -> state
</pre>
<br />
The warning was that the _ -> state rule will never match and I started to wonder if there might be a better way to write this thing.<br />
The ApplicationEvent is defined as follows:<br />
<pre>type ApplicationEvent = ApplicationEvent of EventHeader * obj
</pre>
<i>For those of you that have read my previous posts about <a href="https://dreamstatecoding.blogspot.com/2018/06/functional-adventures-in-f-event.html">Event Sourcing in F# </a>may notice that the event definition has evolved a little bit since my last post in that series, no worries, I will post more when I have something working.</i><br />
<br />
As you can see the ApplicationEvent type is pretty much just a discriminated union of 1 that has a named tuple.<br />
This all makes it easy to handle the application event in the system as one object but when you want to look at the header and payload separately you will have to pattern match it to extract its parts, hence the pattern matching in the function above.<br />
<br />
After a little bit of thinking I tried the following instead:<br />
<pre>let HandleEvent (state:State) (ApplicationEvent (h, p)) : State =
{
CurrentPlayer = CurrentPlayerReducer.HandleEvent state h p
LastEventId = Some h.Id
Timestamp = h.Timestamp
PlayerStore = PlayerReducer.HandleEvent state.PlayerStore h p
SpaceBodyStore = SpaceBodyReducer.HandleEvent state.SpaceBodyStore h p
}
</pre>
I.e. I pattern match already in the in parameters to the function and thus get rid of the whole match construct in the function, and it works!<br />
A day when you learn something new is not a wasted day!<br />
<br />
So hope this helps someone out there!Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1265125331765205173.post-80633559948430353572018-10-17T17:17:00.002+02:002018-10-17T17:19:29.125+02:00Teaching myself Unity - Logging to screen<div class="separator" style="clear: both; text-align: center;">
<img border="0" data-original-height="183" data-original-width="750" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDoUJ59UX_tJkbWOLJmKHYe7XSeskN0lHMWg8Oy9NxiQW3qjxnekX7mtZno4pJ1Mf0UKEfqyebMDU5DwfK0x7ZmEkZRjPILwxEIoq6McBVNtvNf6ovqq3eEvWK4KQmgwmq9n9B9kNiJY0/s1600/header+1.jpg" /></div>
<br />
I've played around quite a lot with OpenGL and built my own engine to some extent (as you can see in other posts on this blog). But I want to create games, doing that with a home-written engine puts a lot of focus on the engine and very little on the actual game. So I decided to try out Unity as it seems popular and has nice integration with Visual Studio<br />
<br />
<br />
<h2>
Getting started</h2>
<ul>
<li><a href="https://visualstudio.microsoft.com/vs/community/">Download Visual Studio Community Edition</a></li>
<li><a href="https://store.unity.com/">Download Unity Personal Edition</a></li>
</ul>
<div>
Install both and start Unity.</div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><img border="0" data-original-height="436" data-original-width="750" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUneMfO-psXqrhLRPSQ0iQCC9XVwJS-5na4oWhjeDCnn7cBX5XXwGIWOckSXXPZ77HnBWt7PgkwPrMX0hH-w598B8iVv7IXqSRCM7L6zLNFvfQjmxfyoGKQVkhtfQJA169FZj9q79Cq9M/s1600/1+Projects.png" style="margin-left: auto; margin-right: auto;" /></td></tr>
<tr><td class="tr-caption" style="text-align: center;">First screen in Unity. Just click on the New button to the upper right to create our first project</td></tr>
</tbody></table>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><img border="0" data-original-height="436" data-original-width="750" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSEnxBbAObdaE2l4ZcK7QbwfaQCnS3tCPkEuZRaYalBgmz0uZkAUV_pxobKteWVR_Gdrxzdu18WFIhMQpQuhgbLhmo3ryLx6DDeo8K2bH_iNlLN0KNsXBxyJrMMFZtuVRN6P_BfX1aKsQ/s1600/2+new+project.png" style="margin-left: auto; margin-right: auto;" /></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Name the project and select where it should be placed on disk. I also disabled unity analytics as I don't think that this test project would have any usage for it.</td></tr>
</tbody></table>
<div>
<br /></div>
<div>
<br /></div>
<h2>
Configure script editor</h2>
<div>
Next step is to make sure that Unity thinks that Visual Studio should be used for script editing</div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0Xi5N9JxMpm9BAaoVPSPCuaV0ndP_Sx9tAEg36nAabyBNEiaIVo2FKqrjVtc8DM5jwsVO0NKQ9F9IpE5X9i53sns794xQMBiXNTKFzuuu_k9WDRkaU-LJwsr3cNGcARyiEnAYD-Omcxg/s1600/3+setting+up+visual+studio+editor.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="432" data-original-width="540" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0Xi5N9JxMpm9BAaoVPSPCuaV0ndP_Sx9tAEg36nAabyBNEiaIVo2FKqrjVtc8DM5jwsVO0NKQ9F9IpE5X9i53sns794xQMBiXNTKFzuuu_k9WDRkaU-LJwsr3cNGcARyiEnAYD-Omcxg/s1600/3+setting+up+visual+studio+editor.png" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Go to Edit menu -> Preferences and in the popup select External Tools and make sure that External Script Editor is set to Visual Studio 2017 (Community). Or any other version of Visual Studio if you have the licensed versions</td></tr>
</tbody></table>
<div>
<br /></div>
<h2>
Logging to screen</h2>
<div>
I like to have stuff happening on the screen, and in my mind the first step should be to add logging to screen so that we can follow what happens in the game without having to tab out to the Unity editor (or when we run the game outside of the development environment)</div>
<div>
So, how to accomplish logging to screen?</div>
<div>
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><img border="0" data-original-height="294" data-original-width="639" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg23sntJw8VcYx3PulpHYyi5VoyK2tBQkPW54KMA7YU8CUEEKRBGyULxojLXGdC7o3u0-GOfMQotFCNlUmQMLn1HP6KncDvy37Ov9NvVcUGR7fElhyphenhyphen97ykWsH3QbmMY4zpBI3mSceAy-7o/s1600/4+create+new+folder.png" style="margin-left: auto; margin-right: auto;" /></td></tr>
<tr><td class="tr-caption" style="text-align: center;">In the project tab. Assets folder, create a new folder and name it Scripts</td></tr>
</tbody></table>
<div>
<ul>
<li>Create a new folder called scripts (see above picture)</li>
<li>Create a new C# script in that folder and call it Logger</li>
</ul>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><img border="0" data-original-height="294" data-original-width="639" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXlNAd66_QTkt1sYvFTBn_BihEojhLr6o21n0UsMwF8oUmJO9L1zreBfdxxqbOJSQLuECkMFGTmPKVhJVSFfIWjXbaE42B8KwT_zYDIcbMhkh1z5gz6hXkJ1BWo7uTd-qZz-K36Lcz7lI/s1600/5+create+new+game+object.png" style="margin-left: auto; margin-right: auto;" /></td></tr>
<tr><td class="tr-caption" style="text-align: center;">In the SampleScene create a new empty GameObject and call it Screen Logger</td></tr>
</tbody></table>
<div>
<ul>
<li>Create a new GameObject and call it Screen Logger</li>
<li>Select the Screen Logger GameObject and drag the Logger script to the Inspector view for the screen logger to attach the script to the GameObject</li>
</ul>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><img border="0" data-original-height="294" data-original-width="639" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwCSFat58OyA97pl76BdvfkbuMePQHJIipj8akwHbKw44bhWJ9wdLC8prh3aDpeAbq2qn9pDqI-AqbEsBb1_AxQW6PcRr0BxNJTcozzuPK9elh4LvQChYzbac0Fuhw5-ilWCTbVN_5B9Q/s1600/6+attach+script+to+game+object.png" style="margin-left: auto; margin-right: auto;" /></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Screen Logger Game Object with attached Logger script in the Inspector view</td></tr>
</tbody></table>
<div>
Next, let's create the UI component that we will log to.</div>
<div>
<ul>
<li>Right click in the Sample Scene tab and select UI -> Text</li>
<li>Rename the newly created Text to Log</li>
</ul>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><img border="0" data-original-height="418" data-original-width="750" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1tnzJLMUuSsjwMxOo3ZdccslfKmhWIO5W5arQIqzpqPStPQH1zKWvld0FWiAhoTe-tPtCtqKZq5VgKr27pOnLOPRlzPF8FgzOA1Wtw384Q9uPrF5_gGI4m9mJSvmpSQpLYy3ncUk_pPE/s1600/7+log+text+and+canvas+in+the+2d+scene+view.png" style="margin-left: auto; margin-right: auto;" /></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Scene view with the Log Text control (New Text), 2D view selected in the upper left corner and the white line is the borders of the canvas</td></tr>
</tbody></table>
<div>
<br /></div>
</div>
<div>
<ul>
<li>Go to the Scene view and click on the 2D button at the top so that we can position our UI component</li>
<li>Select the Log Game Object and move your mouse cursor over the Scene view and press F on the keyboard. This will find and focus the view on that particular component. </li>
<li>Zoom out with your mouse-wheel so that you see the canvas borders</li>
</ul>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><img border="0" data-original-height="171" data-original-width="781" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyo2eyrX-nVhH-a31cWDubZatAKftcgY5IPJg5Yeym8vh62_K9W-N8CdAX3J9IOVOIorSENkPECwyj28srMN0laSGzwyuo_AuDufFzLE5MWAn2jzKeViYYtyZqD2rOFGP0EICT_6nEQCw/s1600/8+resized+textbox+to+fill+the+upper+area+of+the+canvas.png" style="margin-left: auto; margin-right: auto;" /></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Resized textbox to fill the upper area of the canvas</td></tr>
</tbody></table>
<div>
<ul>
<li>Resize the textbox so that it fills the upper area of the canvas. Notice the color change of the canvas border when the textbox is at the border. </li>
</ul>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><img border="0" data-original-height="312" data-original-width="518" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6tiiZAGNfYZJceEzuj-MvinybyjyIIOJICyKAMJg3SEOunVN9vob3nsf-bTBRuKIOh7ZZ5_Mn1VAwUUg3fLhKiSKj4IIXhOZaflfHV3UbQpXrOADRuBF1dQh8_KwD2W0QMVl-EOiVlfQ/s1600/9+stretch+and+anchor+points+for+textbox.png" style="margin-left: auto; margin-right: auto;" /></td></tr>
<tr><td class="tr-caption" style="text-align: center;">In the Inspector, set stretch and anchor to the top of the canvas</td></tr>
</tbody></table>
<div>
<ul>
<li>Select the text box and go to the inspector. Select stretch and anchor point according to the picture above</li>
</ul>
<div>
<br /></div>
</div>
</div>
</div>
<h2>
Logger script</h2>
<div>
So, now we have our UI component setup and placed at the top of the canvas area, lets look at the Logger script.</div>
<pre>using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;</pre>
<pre>public class Logger : MonoBehaviour
{
public static Logger Instance { get; private set; }
public Text Log;
private List<string> _logLines = new List<string>();
void Start()
{
Instance = this;
}
void Update()
{
// test code to check that this works
Write(Time.fixedTime.ToString());
}
public void Write(string text)
{
_logLines.Add(text);
if (_logLines.Count > 3)
_logLines.RemoveAt(0);
Log.text = string.Join(Environment.NewLine, _logLines.ToArray());
}
}
</pre>
<div>
<br />
<ul>
<li>Each script is generated with a Start and Update method. </li>
<li>The static Logger Instance will help us access this script from outside (Singleton pattern). We assign it with this in the Start method (Start is guaranteed to only execute once)</li>
<li>Next we add a using UnityEngine.UI; line to the top and a public variable called Text Log. This will allow us access to an UI component in the scene. We will connect them in a later step, here we just say that we will be using a GameObject of type Text</li>
<li>After that we define a private variable that holds a list of strings that have been logger and initialize it inline</li>
<li>Now, create a new method called Write that takes a string as parameter.</li>
<li>Add the input parameter to the list of strings and then we make sure that the list doesn't grow by removing old items if there are more then 3 items in the collection.</li>
<li>Lastly we join all strings in the list with a new line between each and assign it to the text field of the Text UI component.</li>
</ul>
<div>
And that's pretty much it. You can of course play around with more information but this is the basic logging capability that I am after.</div>
<div>
Notice the Update method calls the Write each frame, this is only for testing purposes and the whole Update method can be removed once we know that the script works.</div>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><img border="0" data-original-height="230" data-original-width="645" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7Vbyx8K69XeDLBUIDgZllSLjaZnmqb1XRWWxyMfU_-0t-hdRfVIaYjbo8tjEZHEkLsAA7vcMgo2vpVWtPAnf7hBO6l1YNOC8FP-jtM8pVFiXLkx8RJIi9mvQx1lSExv5nCTQm1zpTUeY/s1600/10+connect+our+Log+text+element+to+our+Logger+script+in+the+Screen+Logger+game+object+inspection.png" style="margin-left: auto; margin-right: auto;" /></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Connect our Log text element to our Logger script in the Screen Logger game object inspection Click on the small circle to the right of the field to popup the Select Text dialog. It will show all GameObjects in the scene of the type Text.</td></tr>
</tbody></table>
So, our script is done. Now we just have to connect the correct Text component to it<br />
<ul>
<li>In the inspector for Screen Logger, click on the small circle to the right of the Log field to popup the Select Text dialog</li>
<li>As we only have one Text component in the scene at the moment, just select it and close the popup</li>
</ul>
<br />
<br /></div>
<div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><img border="0" data-original-height="127" data-original-width="490" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEii91YabsCsVWrFHIobgI6AVf9QUf1nk7oa0a8foVLIYaefYtFuFfN7pBq-ZTTyCAu8bpw8EfipkADBgI3ryakBTTJariLHfZOFuvxB2j29julqAGjNzY7v3vxdK7f0z2LdvUSZy_FTbUs/s1600/11+test+execution+of+the+screen+logger+component.png" style="margin-left: auto; margin-right: auto;" /></td></tr>
<tr><td class="tr-caption" style="text-align: center;">The end result of our logger in action, currently printing out the time each frame</td></tr>
</tbody></table>
<br /></div>
<div>
So it works, you can now remove the Update method from the script as it is not really needed.<br />
<br />
Usage from other scripts:<br />
<br />
<br /></div>
<pre>Logger.Instance.Write("information that we want to put on screen");
</pre>
</div>
<div>
<br /></div>
</div>
<div>
That's it!</div>
<div>
<br />
<br />
2 great resources that helped me a lot were:<br />
<br />
<ul>
<li><a href="https://shadowplaycoding.com/2016/12/06/lets-make-a-4x-space-game-with-unity-part-1-creating-the-galaxy/">ShadowPlay Coding: Let’s Make a 4X Space Game with Unity!</a></li>
<li><a href="https://catlikecoding.com/unity/tutorials/">Catlike Coding > Unity</a></li>
</ul>
</div>
<div>
</div>
<div>
<br /></div>
<div>
<i>All code provided as-is. This is copied from my own code-base, May need some additional programming to work. Use for whatever you want, how you want! If you find this helpful, please leave a comment or share a link on social media, not required but appreciated! :)</i></div>
<div>
<br /></div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1265125331765205173.post-58026964959925462192018-09-29T16:11:00.000+02:002018-09-29T16:11:00.450+02:00Immutability in .NET<div class="separator" style="clear: both; text-align: center;">
<img border="0" data-original-height="346" data-original-width="750" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheh2fFaaIiwwg9bEDFAmqfA8C03011_JvuXf_MX2iKMpJRb2xzKYRJXZw-tef0IpuWMSlB26vmsqLKtIOEUDTnkfd2Z-CNmCrJB4L5eYQGp0OgjlFJf-xF2ynJNzQkzbv1J1Gcbu6ZS80/s1600/Immutability+in+.NET.jpg" /></div>
<h2>
First off, what are immutable objects</h2>
Immutable is pretty much a fancy word for unchangeable. In other words, once you create an object it will have the same properties for its entire life. No way to reassign for example a name, if you want to do that you would have to create a new object with the same properties but with the new name. <b>Immutable = Not Mutable</b><br />
<h2>
Why bother?</h2>
I didn't understand the point of immutable objects, I though that as long as we encapsulate and follow good object oriented guidelines then we are good to go.. Right?<br />
Let's look at a naive example of things that can go wrong:<br />
<pre>public class CSharpPoco
{
private uint _value;
public uint Value => _value;
public void Increment()
{
_value++;
}
public uint GetNext()
{
Increment();
return _value;
}
}
public class ServiceLayer
{
private CSharpPoco _poco = new CSharpPoco();
public CSharpPoco GetPoco()
{
return _poco;
}
public uint PreviewNextValue()
{
return _poco.GetNext();
}
}
</pre>
<br />
In the service layer we have 2 methods to call, get the poco and preview its next value.<br />
The following service code would throw the side effect exception:<br />
<br />
<pre>var service = new ServiceLayer();
var poco = service.GetPoco();
var firstValue = poco.Value;
var preview = service.GetPreviewValue();
if (preview <= firstValue)
throw new Exception("preview can't be smaller then or equal to the previus value");
if (poco.Value == preview)
throw new Exception("side effect");
</pre>
<br />
Meaning, we get an unexpected side-effect by calling the second method in the service. It manages to change the value of the first service calls result. It was zero, but after the preview call it has been set to 1. This is quite a simple example, but after having debugged scenarios like these in production code with huge code bases.. You get the idea, a unexpected side effect is often a cause for hard-to-find bugs.<br />
So, how could immutability have helped us here? once the var poco = service.GetPoco() was called, the result would never change. Preferably we would not be able to reasign the variable poco to other references either (similar to the <b>const</b> keyword in TypeScript or F# <b>let</b>). So instead of var I would have liked a const poco = service.<br />
<br />
<h2>
What options do we have in .NET?</h2>
<h3>
Readonly objects in C# with constructor lists</h3>
<pre>public class CSharpImmutableConstructorList
{
public readonly Guid Id;
public readonly string Name;
public readonly string DisplayName;
public CSharpImmutableConstructorList(Guid id, string name, string displayName)
{
Id = id;
Name = name;
DisplayName = displayName;
}
public CSharpImmutableConstructorList SetDisplayName(string displayName)
{
return new CSharpImmutableConstructorList(Id, Name, displayName);
}
}
</pre>
Basically the magic here is done by the readonly keyword that states that only the constructor can set the value of the variable. Once it has been set, it can only be read. For larger objects, it can get a little heavy on the constructor and you have to supply all the values every time you want to change. For example the SetDisplayName function, it supplies the Id and Name even though they have the same value as before.<br />
If we add more properties to this class, we would have to change all calls to the constructor and add the new properties for them as well. So a little heavy on the maintenance side.<br />
<br />
<h3>
Readonly objets in C# with Modify pattern</h3>
<pre>public class CSharpImmutableModifyPattern
{
public readonly Guid Id;
public readonly string Name;
public readonly string DisplayName;
public static CSharpImmutableModifyPattern Default { get; } = new CSharpImmutableModifyPattern(Guid.Empty, string.Empty, string.Empty);
private CSharpImmutableModifyPattern(Guid id, string name, string displayName)
{
Id = id;
Name = name;
DisplayName = displayName;
}
public CSharpImmutableModifyPattern Modify(Guid? id = null, string name = null, string displayName = null)
{
return new CSharpImmutableModifyPattern
(
id ?? Id,
name ?? Name,
displayName ?? DisplayName
);
}
public CSharpImmutableModifyPattern SetDisplayName(string displayName)
{
return Modify(displayName: displayName);
}
}
</pre>
This is pretty much the same pattern as I've described in a previous post (<a href="http://dreamstatecoding.blogspot.com/2017/09/functional-adventures-in-net-c-part-1.html">Functional adventures in .NET C# - Part 1, immutable objects</a>), the difference is that we use the readonly members instead of get-only fields.<br />
Also note that the constructor is set to private to prevent usage of it from outside, instead we will use the Default static get-only field that sets up a default invariant of the class and call the new method Modify on it.<br />
The nice thing with the Modify pattern is that you don't have to supply anything else then the changed property as shown in the SetDisplayName method. Even if we add new parameters, we don't have to change the SetDisplayName method as it specifies that it only wants to supply the displayName and nothing else.<br />
<br />
<h3>
Record types in F#</h3>
<pre>module Techdump =
open System
type FSharpRecord =
{
Id : Guid
Name : string
DisplayName : string
}
member this.SetDisplayName displayName =
{ this with DisplayName = displayName }
</pre>
<br />
The F# Record version of the same type as show before. Used from C# this type feels similar to the C# Constructor List version as you have to supply all the constructor parameters when calling new. The magic happens in the SetDisplayName function that takes a new displayName value and then calls the record constructor with the current record and whatever fields have changed. I.e. the with keyword in record construction. We get the power of CSharpImmutableModifyPattern, but without having to maintain a Modify method, it is all included in the language.<br />
<br />
<br />
<h2>
Performance</h2>
<div>
In this part we will look at the run-time performance the different immutable patterns described above. </div>
<h3>
Performance test source code</h3>
<br />
<b>CSharpPoco</b><br />
<pre>public class CSharpPoco
{
public Guid Id { get; private set; }
public string Name { get; private set; }
public string DisplayName { get; private set; }
public CSharpPoco(Guid id, string name, string displayName)
{
Id = id;
Name = name;
DisplayName = displayName;
}
public void SetDisplayName(string displayName)
{
DisplayName = displayName;
}
}
</pre>
Added a C# poco object so that we have a baseline to run against. I.e, here we just mutate the object. No new instance is created, this is the traditional way of changing a value in an object.
<br />
<br />
<b>Performance tester</b><br />
<pre>public class ImmutabilityPerformance
{
public void Execute()
{
Log("--------------------------------------");
Log("... ImmutabilityPerformance");
ExecuteTest(1_000_000);
}
private void ExecuteTest(int iterations)
{
string s = string.Empty;
try
{
var data = new List<string> { "Melissa Lewis", "Maya", "Smith", "Beverly Marsh", "Jane Vasko", "Molly Bloom" };
var csharpPocoTimings = new RunningAverage();
var fsharpRecordTimings = new RunningAverage();
var csharpConstructorTimings = new RunningAverage();
var csharpModifyTimings = new RunningAverage();
for (int i = 0; i < iterations; i++)
{
var csharpPoco = new CSharpPoco(Guid.NewGuid(), "Jessica Chastain", "Jessica Chastain");
var fsharpRecordOriginal = new Techdump.FSharpRecord(Guid.NewGuid(), "Jessica Chastain", "Jessica Chastain");
var csharpConstructorOriginal = new CSharpImmutableConstructorList(Guid.NewGuid(), "Jessica Chastain", "Jessica Chastain");
var csharpModifyOriginal = CSharpImmutableModifyPattern.Default.Modify(Guid.NewGuid(), "Jessica Chastain", "Jessica Chastain");
for (int dataIndex = 0; dataIndex < data.Count; dataIndex++)
{
var item = data[dataIndex];
csharpPocoTimings.Add(TimeAction(() =>
{
csharpPoco.SetDisplayName(item);
}));
if (csharpPoco != null)
s = csharpPoco.DisplayName;
Techdump.FSharpRecord fsharpRecordModified = null;
fsharpRecordTimings.Add(TimeAction(() =>
{
fsharpRecordModified = fsharpRecordOriginal.SetDisplayName(item);
}));
if (fsharpRecordModified != null)
s = fsharpRecordModified.DisplayName;
CSharpImmutableConstructorList csharpConstructorModified = null;
csharpConstructorTimings.Add(TimeAction(() =>
{
csharpConstructorModified = csharpConstructorOriginal.SetDisplayName(item);
}));
if (fsharpRecordModified != null)
s = csharpConstructorModified.DisplayName;
CSharpImmutableModifyPattern csharpModifyModified = null;
csharpModifyTimings.Add(TimeAction(() =>
{
csharpModifyModified = csharpModifyOriginal.SetDisplayName(item);
}));
if (csharpModifyModified != null)
s = csharpModifyModified.DisplayName;
}
}
Log($"CSharpPoco\tIterations:\t{iterations}\tAverage:\t{csharpPocoTimings.Average:0.000}\tticks\tTotal:\t{csharpPocoTimings.Total:0.000}\tticks");
Log($"FSharpRecord\tIterations:\t{iterations}\tAverage:\t{fsharpRecordTimings.Average:0.000}\tticks\tTotal:\t{fsharpRecordTimings.Total:0.000}\tticks");
Log($"CSharpImmutableConstructorList\tIterations:\t{iterations}\tAverage:\t{csharpConstructorTimings.Average:0.000}\tticks\tTotal:\t{csharpConstructorTimings.Total:0.000}\tticks");
Log($"CSharpImmutableModifyPattern\tIterations:\t{iterations}\tAverage:\t{csharpModifyTimings.Average:0.000}\tticks\tTotal:\t{csharpModifyTimings.Total:0.000}\tticks");
}
catch (Exception ex)
{
Log($"Fail\tDataCount\t2\tIterations:\t{iterations}\tFailed\t{ex.Message}");
}
}
private float TimeAction(Action action)
{
var sw = Stopwatch.StartNew();
action();
sw.Stop();
return sw.ElapsedTicks;
}
private void Log(string s)
{
Console.WriteLine(s);
File.AppendAllText(@"c:\temp\enumToStringTest.txt", $"{s}{Environment.NewLine}");
}
}
</pre>
<br />
And the <a href="http://dreamstatecoding.blogspot.com/2016/12/runningaveragehow-to-calculate-average.html">RunningAverage class from a previous post</a>.<br />
<br />
<h2>
Results</h2>
<table border="1" cellpadding="3" cellspacing="3" style="border-collapse: collapse;">
<tbody>
<tr>
<td><div style="text-align: center;">
<b>ImmutabilityPerformance</b></div>
</td>
<td style="width: 97pt;" width="129"><div style="text-align: center;">
<b>Iterations</b></div>
</td>
<td style="width: 103pt;" width="137"><div style="text-align: center;">
<b>Average (ticks)</b></div>
</td>
<td style="width: 95pt;" width="127"><div style="text-align: center;">
<b>Total (ticks)</b></div>
</td>
</tr>
<tr>
<td><b>CSharpPoco</b></td>
<td align="right">1000000</td>
<td align="right">0.090</td>
<td align="right">537402</td>
</tr>
<tr>
<td><b>FSharpRecord</b></td>
<td align="right">1000000</td>
<td align="right">0.121</td><td align="right">727156</td>
</tr>
<tr>
<td><b>CSharpImmutableConstructorList</b></td>
<td align="right">1000000</td>
<td align="right">0.120</td>
<td align="right">720220</td>
</tr>
<tr>
<td><b>CSharpImmutableModifyPattern</b></td>
<td align="right">1000000</td>
<td align="right">0.161</td>
<td align="right">965545</td>
</tr>
</tbody></table>
<br />
Here we can see that the poco baseline test is the fastest by far. Using the F# Record type and C# locked down object with constructor are pretty much equal in execution. The modify pattern in the C# code really drops the performance but gives more readable code, at least if we have long constructor lists in objects.<br />
<h2>
Rewritten increment example</h2>
Let's go back and look at the first increment example again and try to rewrite it with immutability<br />
<pre>public class CSharpImmutable
{
public readonly uint Value;
public CSharpImmutable(uint value)
{
Value = value;
}
public CSharpImmutable Increment()
{
return new CSharpImmutable(Value + 1);
}
public uint GetNext()
{
return Value + 1;
}
}
</pre>
<br />
<b>And in F#</b><br />
<pre>type FsharpIncrement =
{
Value : uint32
}
member this.Increment () =
{ this with Value = this.Value + 1u }
member this.GetNext () =
this.Value + 1u
</pre>
<br />
<h2>
Conclusions</h2>
In my opinion Immutable objects are the way to go if you want to write maintainable code for the long run, what technique you choose is entirely up to you. There are probably other ways to achieve the same that I don't know about, if you have ideas please post a comment!<br />
<br />
After I started writing F# code, and started getting all the immutability features for free and especially the with keyword for records has persuaded me to start writing all my core business models in F#.<br />
<pre>let point' = { point with X = 2; }
</pre>
In my eyes, that line of code just there, is so damn beautiful.<br />
<br />
<br />
<br />
<i>All code provided as-is. This is copied from my own code-base, May need some additional programming to work. Use for whatever you want, how you want! If you find this helpful, please leave a comment or share a link, not required but appreciated! :)</i>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-1265125331765205173.post-72413456556664977972018-09-28T22:48:00.000+02:002018-09-28T22:48:52.881+02:00FSharp Enum ToString vs. C# Enum Dictionary Lookup for Localization<div class="separator" style="clear: both; text-align: center;">
<img border="0" data-original-height="263" data-original-width="750" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicJHDGQnwtGDv3J9nXR3-32XmsWfUWb-D5dZYgAbeDuJQ-aitAxgtXadazi3A8qADkKQtXbECPC0wur1Ma2APrJfqFB_90bgCueA7IV66-nAFnVy0SFk4pxGvuTe3j-wzPAl6mQp2_Ayc/s1600/FSharp+Enum+ToString+vs+C%2523+Enum+Dictionary+Lookup+for+Localization.jpg" /></div>
<br />
I was <a href="http://apollo13cn.blogspot.com/2018/09/f-enums-usage.html" target="_blank">reading Tao Liu's post </a>regarding enums with space for localization to save time and I just had to run a test if this really was faster then defining a lookup table?<br />
<br />
<br />
On my computer<br />
<pre>--------------------------------------
... FsharpEnumToString vs. CSharpEnumDictionaryLookup
FSharpToString Iterations: 10000000; Average: 0,287 ticks; Total: 14374450,000 ticks;
CSharpLookup Iterations: 10000000; Average: 0,134 ticks; Total: 6688315,000 ticks;
</pre>
<br />
So, a simple dictionary lookup is still faster then ToString of a F# enum.<br />
So I'll guess my team will keep the localization as data files / database table that is loaded at runtime into a variable. This way we can outsource the translations to other teams and specialists while keeping the code clean. A misspelled enum member by a tired developer does not result in a hotfix of an application with new builds etc, just a data file update in runtime.<br />
<br />
<br />
The code used to perform this test:<br />
<pre>using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using fsharp.techdump;
namespace techdump.console.Tests
{
public class FsharpEnumToStringVsLookup
{
private Dictionary<CSharpEnum, string> _lookup = new Dictionary<CSharpEnum, string>
{
{ CSharpEnum.Registration, "Registration" },
{ CSharpEnum.UnderReview, "Under Review" },
{ CSharpEnum.Approval, "Approval" },
{ CSharpEnum.Release, "Release" },
{ CSharpEnum.PostRelase, "Post Release" }
};
private enum CSharpEnum
{
Registration = 0,
UnderReview = 1,
Approval = 2,
Release = 3,
PostRelase = 4,
}
public void Execute()
{
Log("--------------------------------------");
Log("... FsharpEnumToString vs. CSharpEnumDictionaryLookup");
ExecuteTest(10_000_000);
}
private void ExecuteTest(int iterations)
{
string s = string.Empty;
try
{
var index = new List<int> { 0, 1, 2, 3, 4 };
var fsharpToStringTimings = new RunningAverage();
var csharpLookupTimings = new RunningAverage();
for (int i = 0; i < iterations; i++)
{
for (int dataIndex = 0; dataIndex < index.Count; dataIndex++)
{
var item = index[dataIndex];
var fsharpEnumMember = (Techdump.FsharpEnum)item;
fsharpToStringTimings.Add(TimeAction(() =>
{
s = item.ToString();
}));
if (!string.IsNullOrEmpty(s))
s = string.Empty;
var csharpEnumMember = (CSharpEnum)item;
csharpLookupTimings.Add(TimeAction(() =>
{
s = _lookup[csharpEnumMember];
}));
if (!string.IsNullOrEmpty(s))
s = string.Empty;
}
}
Log($"FSharpToString\tIterations:\t{iterations}\tAverage:\t{fsharpToStringTimings.Average:0.000}\tticks\tTotal:\t{fsharpToStringTimings.Total:0.000}\tticks");
Log($"CSharpLookup\tIterations:\t{iterations}\tAverage:\t{csharpLookupTimings.Average:0.000}\tticks\tTotal:\t{csharpLookupTimings.Total:0.000}\tticks");
}
catch (Exception ex)
{
Log($"Fail\tDataCount\t2\tIterations:\t{iterations}\tFailed\t{ex.Message}");
}
}
private float TimeAction(Action action)
{
var sw = Stopwatch.StartNew();
action();
sw.Stop();
return sw.ElapsedTicks;
}
private void Log(string s)
{
Console.WriteLine(s);
File.AppendAllText(@"c:\temp\enumToStringTest.txt", $"{s}{Environment.NewLine}");
}
}
}
</pre>
<br />
FSharp Enum defined as follows:<br />
<pre>namespace fsharp.techdump
module Techdump =
type public FsharpEnum =
Registration = 0
| ``Under Review``=1
| Approval = 2
| Release = 3
| ``Post Release`` = 4
</pre>
<br />
<br />
And the <a href="http://dreamstatecoding.blogspot.com/2016/12/runningaveragehow-to-calculate-average.html">RunningAverage class from a previous post</a>.<br />
<br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1265125331765205173.post-86420994252590383842018-09-26T21:22:00.001+02:002018-09-26T21:22:52.576+02:00GeoCoordinateWatcher and GMap.NET<div class="separator" style="clear: both; text-align: center;">
<img border="0" data-original-height="315" data-original-width="750" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1RSUFGwfaJ0V3wg8CHHsJdmYsLLaZC1fHho7pqdjwuv8IBif-irvaYgEYBTeHg46HLsJqSyLiqmJunElNGGeooWMRP_d685IC-OmlOKNQ0Ub7tF-kIEe7G9m5Gy-pkxHf-lyfre8F5WE/s1600/GeoCoordinateWatcher+and+GMapNET.jpg" /></div>
Playing around a little with the <a href="https://www.nuget.org/packages/GMap.NET.Windows/" target="_blank">GMap.NET - Maps For Windows</a> and figured I would use my computers location as a startup point for the map view.<br />
Ended up encapsulating System.Device.Location.GeoCoordinateWatcher in a static class to get around the NaN coordinates returned from an uninitialized GeoCoordinateWatcher as it turns out that GMap.NET doesn't like NaN at all.<br />
<pre>using System.Device.Location;
namespace dreamstatecoding.blogspot.com
{
public static class GeoProvider
{
private static GeoCoordinateWatcher _watcher = new GeoCoordinateWatcher();
public static bool IsInitialized { get; private set; }
static GeoProvider()
{
_watcher.PositionChanged += _watcher_PositionChanged;
_watcher.Start();
}
public static void Cleanup()
{
_watcher.Stop();
_watcher.Dispose();
_watcher = null;
}
private static void _watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
{
IsInitialized = true; ;
}
public static GeoCoordinate GetCoordinates()
{
var coordinates = _watcher.Position.Location;
if (double.IsNaN(coordinates.Latitude))
return new GeoCoordinate(0, 0);
return coordinates;
}
}
}
</pre>
Usage: Giving the provider some time to get hold of the first coordinates. If it doesn't, the coordinate returned would be longitude:0;latitude:0. So pretty much in the ocean outside of Africa.<br />
<pre>private void SetupMap()
{
for(int i = 0; i < 1000; i++)
{
if (GeoProvider.IsInitialized)
break;
Thread.Sleep(151);
}
var coordinates = GeoProvider.GetCoordinates();
gmap.MapProvider = GMapProviders.GoogleMap;
gmap.Position = new PointLatLng(coordinates.Latitude, coordinates.Longitude);
gmap.MinZoom = 0;
gmap.MaxZoom = 24;
gmap.Zoom = 15;
}
</pre>
<br />
It seems that the thread in the GeoCoordinateWatcher is not set to Background as default. So I just force kill it when the application shuts down for now. I put this in my Program.cs file in the WinForms project:<br />
<pre>[STAThread]
static void Main()
{
Application.ApplicationExit += Application_ApplicationExit;
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
private static void Application_ApplicationExit(object sender, EventArgs e)
{
GeoProvider.Cleanup();
}
</pre>
<br />
<br />
<i>All code provided as-is. This is copied from my own code-base, May need some additional programming to work. Use for whatever you want, how you want! If you find this helpful, please leave a comment or share a link, not required but appreciated! :)</i>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-1265125331765205173.post-87251675100732942632018-09-26T14:04:00.000+02:002018-09-26T14:04:19.510+02:00The elegance of a F# WebRequest<div class="separator" style="clear: both; text-align: center;">
<img border="0" data-original-height="349" data-original-width="750" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDETM0-Xgay2NjKsanQg6rWSu_LMeWdPrgPe27BLV7sAgD4jnAK_iHKYVajnOIk8efYBrqXHrOzVq-e9Oy9lIzNgiz3zJdeMRP0xOVyGMFbbQIxLYAjwraRM94vj926Wk9KJkx7rs661U/s1600/the+elegance+of+a+fsharp+webrequest.jpg" /></div>
<br />
Love the elegance of doing a WebRequest in F#<br />
<br />
<pre>module WebLoader =
open System.Net
open System.IO
let GetString (url:string) =
let request = WebRequest.Create(url)
use response = request.GetResponse()
use stream = response.GetResponseStream()
use reader = new StreamReader(stream)
reader.ReadToEnd()
</pre>
<br />
Especially the <b>use</b> keyword compared to the C# <b>using { } </b>blocks. Me like!Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-1265125331765205173.post-8221227526713214492018-06-20T11:46:00.000+02:002020-03-10T12:56:39.785+01:00Functional Adventures in F# - Event sourcing lessons learned<div class="separator" style="clear: both; text-align: center;">
<img border="0" data-original-height="421" data-original-width="750" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYM__1Z2iyAT8tLY1_OrBDa9mO4NXBd8Xqg1GqTfYLPi1RsBAGq6wFzOXY-KNDukWRhj_PoVZggXnggLqtseFBk1Ih79G42xFZeNX0qdHjRztLS7bjOLDuOJSlyC3Projj0LARL0vM0fA/s1600/event+sourcing+lessons+learned.jpg" /></div>
6 things I wish I knew before starting with event sourcing<br />
<br />
Thought I'd write something about the pitfalls that I've stumbled across when using my event sourcing engine.<br />
<br />
<b>This post is part of a series:</b><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-simple.html">Functional Adventures in F# - A simple planner</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-calling-f.html">Functional Adventures in F# - Calling F# from C#</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-using-map.html">Functional Adventures in F# - Using Map Collections</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-application.html">Functional Adventures in F# - Application State</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-types-with.html">Functional Adventures in F# - Types with member functions</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-getting-rid.html">Functional Adventures in F# - Getting rid of loops</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-getting-rid_22.html">Functional Adventures in F# - Getting rid of temp variables</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/04/functional-adventures-in-f.html">Functional Adventures in F# - The MailboxProcessor</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/05/functional-adventures-in-f-persisting.html">Functional Adventures in F# - Persisting Application State</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/05/functional-adventures-in-f-adding.html">Functional Adventures in F# - Adding Snapshot Persisting</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/06/functional-adventures-in-f-type-safe.html">Functional Adventures in F# - Type-safe identifiers</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/06/functional-adventures-in-f-event.html">Functional Adventures in F# - Event sourcing lessons learned</a><br />
<br />
<h2>
Using domain objects in actions</h2>
The first actions that I used basically had me create the domain objects on the outside and then plug them into the create action. The store only took the object and placed it in the stores Map over objects.<br />
<pre>type AddUser = { ActionId: Guid; User : User }
type UserStore =
{
Users: Map<UserId, User>
}
member this.AddUser (action:AddUser)=
{ this with Users = this.Users.Add(action.User.Id, action.User); }
member this.HandleAction (action:obj) =
match action with
| :? AddUser as a -> this.AddUser a
| _ -> this
</pre>
This makes your domain model a part of the persistence layer (as all actions are persisted). I.e. you cannot change your model without getting nifty errors (like null exceptions)<br />
You might think that: You still persist snapshots of the whole ApplicationState, i.e. the User object ends up in persistence.<br />
True. But when you do 'model breaking changes', you could just remove all snapshots and then rerun all actions from the start and get the equivalent state as you did before the breaking change. If you in turn include the domain object in the actions, you are screwed.<br />
A better way to write this would be:<br />
<pre>type AddUser = { ActionId: Guid; UserId : UserId; Name:string; Email:string }
type UserStore =
{
Users: Map<UserId, User>
}
member this.AddUser (action:AddUser)=
let user =
{
Id = action.UserId
Name = action.Name
Email = action.Name
}
{ this with Users = this.Users.Add(user.Id, user); }
</pre>
<br />
<br />
<br />
<h2>
Creating identifiers in stores</h2>
When creating a new object in a store based on an action, at times I forget and do thing like this:<br />
<pre>member this.AddUser (action:AddUser)=
let user =
{
Id = UserId (Guid.NewGuid())
Name = action.Name
Email = action.Name
}
{ this with Users = this.Users.Add(user.Id, user); }
</pre>
The end result works the first time. But if you restart the service and Replay actions, then you will end up with a different Identifier for the User object in this case. All actions that want to use this object and refer to it by its Identifier, will not find a match after a replay. Not a good thing<br />
A better way to write this would be:<br />
<pre>type AddUser = { ActionId: Guid; UserId : UserId; Name:string; Email:string }
type UserStore =
{
Users: Map<UserId, User>
}
member this.AddUser (action:AddUser)=
let user =
{
Id = action.UserId
Name = action.Name
Email = action.Name
}
{ this with Users = this.Users.Add(user.Id, user); }</pre>
This way, when we want to create a new user, the code that creates the AddUser action (maybe your ASP.NET Core MVC Controller, needs to generate the Id, but in turn the Id will be persisted with the action and will be the same even after a replay<br />
<br />
<h2>
Assuming that things exist in the store</h2>
Not all things are eternal. So just because there is an action arriving that thinks that there exists an object in the store does not mean that there actually is one. Another action could have removed it between that the first action was created and processed.<br />
<pre>member this.ModifyUser (action:ModifyUser)=
let original = this.Users.[action.UserId]
let updated = { original with Name = action.Name; Email = action.Email }
{ this with Users = this.Users.Add(updated.Id, updated); }
</pre>
The code above would throw an KeyNotFoundException if the key doesn't exist in the Map.<br />
A better way to write this would be to try to find the object.<br />
<pre>member this.ModifyUser (action:ModifyUser)=
let o = this.Users.TryFind action.UserId
match o with
| None -> this
| Some original ->
let updated = { original with Name = action.Name; Email = action.Email }
{ this with Users = this.Users.Add(updated.Id, updated); }
</pre>
Here we use the Map.TryFind function that returns None or Some x. If the key doesn't exist and we receive None, we jut return the current state as the new state.<br />
If we got an hit, the Some original case would be hit and we can plug in the original code there.<br />
<br />
<h2>
Is it an event or a query?</h2>
I'm writing a game... Is each frame a new event that recalculates all positions of game objects... In the first version that was the case.<br />
<pre>type ShipUpdateCoordinates = { ActionId: Guid; Timestamp:DateTime; ShipId: ShipId; NewPosition:Vector3; }
</pre>
Turns out that in 60 fps, there will be a lot of events persisted.<br />
<br />
So. Instead of updating the position of each object in 60 fps. Then only event that is persisted is based on user input (or when the game engine decides to change the direction of an NPC object)<br />
<pre>type ShipFlyTo = { ActionId: Guid; Timestamp:DateTime; ShipId: ShipId; Origin:Vector3; Target:Vector3; }
</pre>
The rendering engine will query<br />
<pre>type TravelPlan =
{
Origin : Vector3
Target : Vector3
SpeedMetersPerSecond : float
TravelStarted : DateTime
}
member this.Distance () = this.Origin.distance this.Target
member this.TravelTimeSeconds () =
match this.SpeedMetersPerSecond with
| 0. -> 0.
| _ -> this.Distance() / this.SpeedMetersPerSecond
member this.Eta () =
match this.TravelTimeSeconds() with
| 0. -> DateTime.UtcNow
| a -> this.TravelStarted.AddSeconds(a)
member this.GetCoordinates (now:DateTime) =
let eta = this.Eta()
let percentage = PercentageOfValueBetweenMinAndMax (float this.TravelStarted.Ticks) (float eta.Ticks) (float now.Ticks)
this.Origin.lerp this.Target (percentage/100.)
</pre>
I.e. we know then the event occurred and what time it is now. That way we can calculate the current position of the object based on its speed and assuming it is traveling at constant speed by using <a href="https://en.wikipedia.org/wiki/Linear_interpolation" target="_blank">linear interpolation (lerp)</a><br />
The rendering engine can query the model as many times per second as it wants without having to store the new coordinates. As the ApplicationState is immutable and lock-free, we can do this without affecting event processing.<br />
<br />
<h2>
First time start?</h2>
I wanted to generate a game world on the first time start. I tried to use the processed events counter. Turns out as all processing is running on a different thread (as a MailboxProcessor), there is a race condition. And sometimes we just generate 2 worlds.. Not a good thing<br />
Hence I updated the AppHolder class<br />
<pre>let mutable private hasReplayed : bool = false;
let IsFirstTimeUse() = not hasReplayed
let private HandleReplayAction (action:obj, id:Guid) =
hasReplayed <- true
Processor.Post (Replay action)
</pre>
This way, in my Program.cs that handles the startup I can just write this to ensure that the game world is generated on the first use.<br />
<pre>AppHolder.InitiateFromLastSnapshot();
if (AppHolder.IsFirstTimeUse())
GameBasicDataCreator.CreateOnFirstTimeStart();
</pre>
<br />
<h2>
When do I start the Game engine</h2>
A similar question, but took me too long to figure out it even happened.<br />
<pre>AppHolder.InitiateFromLastSnapshot();
if (AppHolder.IsFirstTimeUse())
GameBasicDataCreator.Create();
_engine.Start();
</pre>
Here, we start the game engine when there is a race condition that Replay events are still being processed on another thread. The game engine will start analyzing the game state and reacting to things it see. I.e. not a good thing<br />
<br />
Another change was needed in the AppHolder to fix this<br />
<pre>let mutable private replayCompleted : bool = false;
let IsReplayCompleted() = replayCompleted
type Message =
| Snapshot of AppliationState
| Replay of obj
| ReplayCompleted
| Action of obj
</pre>
For starters we add new public function so that we can query if the Replay is completed. We also add a new internal Message union case ReplayCompleted.<br />
<pre>let private Processor = MailboxProcessor.Start(fun inbox ->
let rec loop (s : AppliationState, c : int) =
async {
let! message = inbox.Receive()
let c' = c + 1
let s' =
match message with
| Snapshot snapshot -> snapshot
| Replay a -> s.HandleAction a
| ReplayCompleted ->
replayCompleted <- true
s
| Action a ->
AppPersister.Persist a s c'
s.HandleAction a
state <- s'
counter <- c'
return! loop (s', c')
}
loop (AppliationState.Default, 0))
</pre>
Next we change our MailboxProcessor code to include the handling for the new union case. We just set the mutable value to true from false.<br />
<pre>let InitiateFromLastSnapshot () =
let (snapshot, actions) = AppPersister.GetLatestSnapshotAndActions()
match snapshot with
| Some x -> Processor.Post (Snapshot x)
| _ -> ()
Array.map (fun x -> (HandleReplayAction x)) actions |> ignore
if hasReplayed then Processor.Post ReplayCompleted
let InitiateFromActionsOnly () =
AppPersister.GetAllActions()
|> Array.map (fun x -> (HandleReplayAction x))
|> ignore
if hasReplayed then Processor.Post ReplayCompleted
</pre>
And lastly, we change our 2 initialize functions to send in the ReplayCompleted message to the MailboxProcessor if there were any Replayed actions at all<br />
In our initialization code in Program.cs we can now add some extra checks if there was any replaying done so that we actually wait for them all to be completed before continuing
<br />
<pre>AppHolder.InitiateFromLastSnapshot();
if (!AppHolder.IsFirstTimeUse())
{
while (!AppHolder.IsReplayCompleted())
Thread.Sleep(100);
}
</pre>
<br />
<br />
That is it!<br />
AppHolder updates have been uploaded to <a href="https://github.com/eowind/dreamstatecoding/tree/master/dreamstatecoding.functionalcore/eventsourcing" target="_blank">github</a>.<br />
<br />
<i>All code provided as-is. This is copied from my own code-base, May need some additional programming to work. Use for whatever you want, how you want! If you find this helpful, please leave a comment or share a link, not required but appreciated! :)</i><br />
<br />
Hope this helps someone out there!Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1265125331765205173.post-30212660879145799302018-06-05T13:00:00.001+02:002018-10-12T22:20:05.908+02:00Functional Adventures in F# - Type-safe identifiers<div class="separator" style="clear: both; text-align: center;">
<img border="0" data-original-height="421" data-original-width="750" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVFUfk5ZH3k0F9_TfM8eI_riVAkQYOKf_ZwKwbA3pEMNxvhJpQm9ceXoAVznti1jWqlJtCtUslDWPPPoHoTfmb8LkhtA7yT0obCiQ0HaGRGicDnQC-X545a47bNmJ1GW8cW21ckU_DQOE/s1600/type-safe+identifiers.jpg" /></div>
<br />
In this post we will look at type-safe identifiers for things.<br />
<br />
<b>This post is part of a series:</b><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-simple.html">Functional Adventures in F# - A simple planner</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-calling-f.html">Functional Adventures in F# - Calling F# from C#</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-using-map.html">Functional Adventures in F# - Using Map Collections</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-application.html">Functional Adventures in F# - Application State</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-types-with.html">Functional Adventures in F# - Types with member functions</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-getting-rid.html">Functional Adventures in F# - Getting rid of loops</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-getting-rid_22.html">Functional Adventures in F# - Getting rid of temp variables</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/04/functional-adventures-in-f.html">Functional Adventures in F# - The MailboxProcessor</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/05/functional-adventures-in-f-persisting.html">Functional Adventures in F# - Persisting Application State</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/05/functional-adventures-in-f-adding.html">Functional Adventures in F# - Adding Snapshot Persisting</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/06/functional-adventures-in-f-type-safe.html">Functional Adventures in F# - Type-safe identifiers</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/06/functional-adventures-in-f-event.html">Functional Adventures in F# - Event sourcing lessons learned</a><br />
<br />
So, working on my game I just used to define identifiers like for example ShipId like the following:<br />
<pre>type ShipId = Guid
type Ship =
{
Id : ShipId
Name : string
}
let ship = { Id : Guid.NewGuid(); Name : "Nebuchadnezzar" }
</pre>
Turns out this was not the best way to do things. From C# code you can just send in any Guid, nothing is typed. And you can assign a 'ShipId' to a 'UserId' in F# as well, as it is just a type alias. I found out that a hard way while tracking down a bug that turned out to be a copy paste issue.<br />
<br />
So, now that I have a bunch of stuff already written, I had to change this to a single item discriminated union. Took a while but it seems to work much better with the type-safety.. The way I thought that I thought it already did.<br />
<br />
So, lets redefine the ShipId as a single item discriminated union like<br />
<pre>type ShipId = ShipId of Guid
</pre>
The code to use it from code is like:<br />
<pre>let ship = { Id : ShipId (Guid.NewGuid()); Name : "Nebuchadnezzar" }
</pre>
<br />
<br />
<h2>
Usage from C#</h2>
My game is partially written in C# as it just works better for some tasks. So interfacing with the new typed ids will be like:<br />
<br />
Getting the underlying Guid<br />
<pre>var shipIdGuid = ship.Id.Item,
</pre>
Creating a new ShipId from a Guid<br />
<pre>var shipId = ShipId.NewShipId(Guid.NewGuid());
</pre>
<br />
So a little bit more hassle from C#, but not that much, and most of my code is just service layer code creating F# records from external input. And the little extra overhead is worth it for the type-safety!<br />
<br />
<i>All code provided as-is. This is copied from my own code-base, May need some additional programming to work. Use for whatever you want, how you want! If you find this helpful, please leave a comment or share a link on social media, not required but appreciated! :)</i><br />
<br />
Hope this helps someone out there!<br />
Follow my preparation for <a href="https://dreamstateadventures.blogspot.com/2018/08/stelvio-2019-start-of-plan.html">adventure cycling through Europe</a>!<br />
<br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1265125331765205173.post-13616116798692861012018-05-18T21:41:00.002+02:002020-03-10T12:56:18.512+01:00Functional Adventures in F# - Adding Snapshot Persisting<div class="separator" style="clear: both; text-align: center;">
<a href="https://dreamstatecoding.blogspot.com/2018/05/functional-adventures-in-f-adding.html"><img border="0" data-original-height="421" data-original-width="750" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgU5fkWvLMJbGvylCj3-xPE_Xyqye-1NjPehC6ji6A0FDIWS9aVBtVRcRhM_rG47hs1d8jqIs7IYkWK3zuxTJsKBkDyjOnMQcbnUG4qEZSJaQRXD6nmLQMDfy_WU-LEj_MhVhznvxjKRbc/s1600/Adding+Snapshot+Persisting.jpg" /></a></div>
<br />
<br />
In this post we will look at how to add snapshots to our event source engine from previous posts.<br />
<br />
<b>This post is part of a series:</b><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-simple.html">Functional Adventures in F# - A simple planner</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-calling-f.html">Functional Adventures in F# - Calling F# from C#</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-using-map.html">Functional Adventures in F# - Using Map Collections</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-application.html">Functional Adventures in F# - Application State</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-types-with.html">Functional Adventures in F# - Types with member functions</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-getting-rid.html">Functional Adventures in F# - Getting rid of loops</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-getting-rid_22.html">Functional Adventures in F# - Getting rid of temp variables</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/04/functional-adventures-in-f.html">Functional Adventures in F# - The MailboxProcessor</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/05/functional-adventures-in-f-persisting.html">Functional Adventures in F# - Persisting Application State</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/05/functional-adventures-in-f-adding.html">Functional Adventures in F# - Adding Snapshot Persisting</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/06/functional-adventures-in-f-type-safe.html">Functional Adventures in F# - Type-safe identifiers</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/06/functional-adventures-in-f-event.html">Functional Adventures in F# - Event sourcing lessons learned</a><br />
<br />
<br />
Quickest way to get started for me was to just persist a snapshot every X actions that were processed. Also for my needs, it is OK to persist the snapshot on a separate thread, as long as the actions are persisted by the AppHolder MailboxProcessor, then the snapshot can be written by another MailboxProcessor. This way, as the state grows it will not affect the main processing...<br />
<br />
Changes needed to the AppPersister<br />
<br />
We will be adding a new function called Persist that will be called from the AppHolder instead of the current PersistAction.<br />
<pre> let Persist (nextAction:obj) (state:obj) (actionCounter:int) =
PersistAction nextAction nextAction?ActionId
PersistSnapshot actionCounter state nextAction?ActionId
()
</pre>
This in turn will call 2 functions, the old PersistAction from previous part and the new PersistSnapshot.<br />
Also, note the nextAction?ActionId, this is part of the FSharp.Interop.Dynamic NuGet package that adds the support for Dynamics, i.e. runtime checked fields and functions on objects instead of compile time checked types. We will be assuming that all actions (that are of type object, or obj in F#) implement the field ActionId... We could solve this by forcing an interface implementation but that just gives us ugly code here, but I guess there is a better solution but for me this solved the problem and I am only to blame myself if things break.<br />
Use them with care.<br />
<br />
<pre> let private Snapshotter = MailboxProcessor.Start(fun inbox ->
let rec loop (n:int) =
async {
let! (actionCounter:int,state:obj, nextActionId:Guid) = inbox.Receive()
if actionCounter % 300 = 0 then
writeSnapshotToDisk state nextActionId
return! loop n
}
loop 0)
let PersistSnapshot (actionCounter:int) (state:obj) (nextActionId:Guid) =
Snapshotter.Post (actionCounter, state, nextActionId)
</pre>
<br />
The PersistSnapshot function just posts the state to the MailboxProcessor called Snapshotter that in turn calls writeSnahotToDisk every 300 action. Much hardcoded here, I guess you will have to experiment a little to find the magic number that works for you (300 is just an example and I will probably end changing it in my code as well)<br />
<pre> let private createSnapshotFilename (nextActionId:Guid) =
let now = DateTime.UtcNow
let dayPath = now.ToString("yyyy-MM-dd")
let fullPath = Path.Combine(store, "snapshots", dayPath)
let di = new DirectoryInfo(fullPath)
di.Create()
let filename = now.ToString("yyyy-MM-dd hh_mm_ss_fffffff.") + nextActionId.ToString() + ".snapshot"
let fullFilename = Path.Combine(fullPath, filename)
fullFilename
let private writeSnapshotToDisk (state:obj) (nextActionId:Guid) =
let fullFilename = createSnapshotFilename nextActionId
let json = JsonConvert.SerializeObject(state)
File.WriteAllText(fullFilename, json)
()
</pre>
<br />
So basically as in the PersistAction part, we add some meta-data to the filename that we can use when reading from disk later. We JSON serialize the state object just as it is. The meta-data that we are interested in is the <b>ID of the next action</b> to be executed.<br />
<br />
<br />
We will also be changing the createActionFilename function to add the ID of the action to the filename as follows:<br />
<pre> let private createActionFilename (action:obj) (actionId:Guid) =
let now = DateTime.UtcNow
let hourPath = now.ToString("yyyy-MM-dd HH")
let fullPath = Path.Combine(store, hourPath)
let di = new DirectoryInfo(fullPath)
di.Create()
let t = action.GetType()
let filename = now.ToString("yyyy-MM-dd hh_mm_ss_fffffff+") + now.Ticks.ToString() + "." + t.Name + "." + actionId.ToString() + ".action"
let fullFilename = Path.Combine(fullPath, filename)
fullFilename
</pre>
<br />
<br />
Next we will be adding functionality to load snapshots and actions from disk. I.e. latest snapshot and all actions persisted after that snapshot. A totality that will result in a total state.<br />
<br />
First, a minor change to getAction<br />
<pre> let private getAction (json:string, filename:string) =
let split = filename.Split('.')
let actionName = split.[1]
let actionNameWithNamespace = "dreamstatecoding.core.Actions+" + actionName
let t = Assembly.GetExecutingAssembly().GetType(actionNameWithNamespace)
(JsonConvert.DeserializeObject(json, t), Guid.Parse(split.[2]))
</pre>
We will be returning a tuple, with the deserialized object as the first element and the ID as the second element<br />
<br />
Next, we want to get all actions from a specific ID, namely the ID that we wrote into the filename of the snapshot. To do this we do the following:<br />
<pre> let private fileContainAction (filename:string) (actionIdString:string) =
let split = filename.Split('.')
split.[2] = actionIdString
let GetAllActionsFromId (nextActionId:Guid) =
let di = new DirectoryInfo(store)
di.Create()
let nextActionIdString = nextActionId.ToString()
let actions =
di.GetFiles("*.action", SearchOption.AllDirectories)
|> Seq.skipWhile (fun (fi:FileInfo) -> not (fileContainAction fi.Name nextActionIdString))
|> Seq.map (fun (fi:FileInfo) -> File.ReadAllText(fi.FullName), fi.Name)
|> Seq.map (fun x -> (getAction x))
|> Seq.toArray
actions
</pre>
We use the Seq.skipWhile that skips elements in the input sequence until the function returns false, after that it will return the rest of the sequence. In our case, we check if the filename contains the next action id with the help of the fileContainsAction function and negating the result by using the <b>not </b>operator.<br />
Handy when the framework contians these nice functions that do exactly what you need at the moment!<br />
<pre> let private getSnapshot (fi:FileInfo) =
let split = fi.Name.Split('.')
let json = File.ReadAllText(fi.FullName)
(JsonConvert.DeserializeObject<ApplicationState.AppliationState>(json), Guid.Parse(split.[1]))
</pre>
The getSnaphot is pretty much the same as the GetAction, we parse out the <b>ID of the next action</b> to be executed from the filename and return a tuple of the deserialized state and the ID.<br />
<br />
And lastly the new function to be called from outside to get the latest state from disk storage:<br />
<pre> let GetLatestSnapshotAndActions () =
let di = new DirectoryInfo(Path.Combine(store, "snapshots"))
di.Create()
let fileInfos = di.GetFiles("*.snapshot", SearchOption.AllDirectories)
match fileInfos with
| a when a.Length = 0 -> (None, GetAllActions())
| _ ->
let (snapshot, nextActionId) =
fileInfos
|> Seq.last
|> getSnapshot
let actions = GetAllActionsFromId nextActionId
(Some snapshot, actions)
</pre>
Key things to note here:<br />
<br />
<ul>
<li>We create the snapshot directory if it does not exist, this so that we don't get 'directory does not exist' exceptions from the GetFiles method.</li>
<li>If there are no files returned by the GetFiles method, we return a tuple with None as the first element and the original GetAllActions as the actions list to be executed.</li>
<li>otherwie we get the last snapshot (Seq.last) and return Some snapshot, and reminder of actions as a tuple</li>
</ul>
<div>
The None and Some way of doing things seems nicer then using null as we do in other languages, especially from the caller side as we will see in our rewritten AppHolder module:</div>
<br />
<pre> type Message =
| Snapshot of AppliationState
| Replay of obj
| Action of obj
</pre>
First we introduce a new message type to our MailboxProcessor, the Snapshot of ApplicationState.<br />
<pre>let s' =
match message with
| Snapshot snapshot -> snapshot
| Replay a -> s.HandleAction a
| Action a ->
AppPersister.Persist a s c'
s.HandleAction a
</pre>
If it is a snapshot, then the<b> s' state is the snapshot</b>, i.e. no other processing is done<br />
Then, lastly we add a new init function to be called from our application startup code (Program.cs or whatever you are using)<br />
<br />
<pre> let InitiateFromLastSnapshot () =
let (snapshot, actions) = AppPersister.GetLatestSnapshotAndActions()
match snapshot with
| Some x -> Processor.Post (Snapshot x)
| _ -> ()
Array.map (fun x -> (HandleReplayAction x)) actions
</pre>
Here we get the snapshot and actions from the AppPersister, then we use pattern matching on the snapshot to determine if it is Some, in which case we send it into the Processor as a Snapshot message. Otherwise we do nothing ()<br />
And then just run in all the Replay actions as before.<br />
<br />
<br />
<br />
That is it!<br />
All code is available at <a href="https://github.com/eowind/dreamstatecoding/tree/master/dreamstatecoding.functionalcore/eventsourcing" target="_blank">github</a>.<br />
<br />
<h2>
Known issues</h2>
<h4>
Newtonsoft JSON.NET typeconverter issue</h4>
Newtonsoft JSON.NET seems to have some trouble with F# Map collections, especially when using union types as keys<br />
<pre>type UserId = UserId of Guid.
Map<UserId, User></pre>
Gives following nasty exception when trying to deserialize it as a key in a Map<br />
<pre>Newtonsoft.Json.JsonSerializationException
HResult=0x80131500
Message=Could not convert string 'UserId 8fa6d5a6-9500-4aac-9f3e-a5b918b81c46' to dictionary key type 'dreamstatecoding.core.Model+UserId'. Create a TypeConverter to convert from the string to the key type object. Path 'UserStore.Users['UserId 8fa6d5a6-9500-4aac-9f3e-a5b918b81c46']', line 1, position 69.
Source=Newtonsoft.Json
StackTrace:
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateDictionary(IDictionary dictionary, JsonReader reader, JsonDictionaryContract contract, JsonProperty containerProperty, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ResolvePropertyAndCreatorValues(JsonObjectContract contract, JsonProperty containerProperty, JsonReader reader, Type objectType)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, ObjectConstructor`1 creator, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ResolvePropertyAndCreatorValues(JsonObjectContract contract, JsonProperty containerProperty, JsonReader reader, Type objectType)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, ObjectConstructor`1 creator, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
at dreamstatecoding.core.AppPersister.getSnapshot(FileInfo fi) in C:\tfs\apps\dreamstatecoding.core\AppPersister.fs:line 104
at dreamstatecoding.core.AppPersister.GetLatestSnapshotAndActions() in C:\tfs\apps\dreamstatecoding.core\AppPersister.fs:line 113
at dreamstatecoding.core.AppHolder.InitiateFromLastSnapshot() in C:\tfs\apps\dreamstatecoding.core\AppHolder.fs:line 47
at test.web.Program.Main(String[] args) in C:\tfs\apps\test\test.web\Program.cs:line 14
Inner Exception 1:
JsonSerializationException: Error converting value "UserId 8fa6d5a6-9500-4aac-9f3e-a5b918b81c46" to type 'dreamstatecoding.core.Model+UserId'. Path 'UserStore.Users['UserId 8fa6d5a6-9500-4aac-9f3e-a5b918b81c46']', line 1, position 69.
Inner Exception 2:
ArgumentException: Could not cast or convert from System.String to dreamstatecoding.core.Model+UserId.
</pre>
This is fixed and a new version is on <a href="https://github.com/eowind/dreamstatecoding/tree/master/dreamstatecoding.functionalcore/eventsourcing" target="_blank">github</a>.. Thanks to the really nice #fsharp community on twitter for the help!<br />
Code changes to include the Fable.JsonConverter<br />
<pre>let converters =
[ Fable.JsonConverter () :> JsonConverter ] |> List.toArray :> IList<JsonConverter>
let settings =
JsonSerializerSettings (
Converters = converters,
Formatting = Formatting.Indented,
NullValueHandling = NullValueHandling.Ignore)
</pre>
And then just using it in serializing and deserializing as follows:<br />
<pre>let json = JsonConvert.SerializeObject(state, settings)
let newState = JsonConvert.DeserializeObject<ApplicationState.ApplicationState>(json, settings)
</pre>
<br />
<i>All code provided as-is. This is copied from my own code-base, May need some additional programming to work. Use for whatever you want, how you want! If you find this helpful, please leave a comment, not required but appreciated! :)</i><br />
<br />
Hope this helps someone out there!Unknownnoreply@blogger.com4tag:blogger.com,1999:blog-1265125331765205173.post-72410069680152129942018-05-09T18:59:00.002+02:002020-03-10T12:56:04.922+01:00Functional Adventures in F# - Persisting Application State<div class="separator" style="clear: both; text-align: center;">
<img border="0" data-original-height="421" data-original-width="750" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzu9geLLPmrI1-s8TF2FI9pYE6SgWLE7K154HavMDJ0XQxROYyiTcP1F-bJoABjv75Wj8z4J8FTU68BAQU81M3-ao7oxMmyyZ0UHdqm_r6DaH24xHGErDt6ZQ-bzdi0hWyIs1Ju_AuzE8/s1600/Persisting+Application+State.jpg" /></div>
<br />
<br />
In this part we will look at how to persist the application state to disk. It should not be too hard to modify for usage with other persistence solutions.<br />
<br />
<b>This post is part of a series:</b><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-simple.html">Functional Adventures in F# - A simple planner</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-calling-f.html">Functional Adventures in F# - Calling F# from C#</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-using-map.html">Functional Adventures in F# - Using Map Collections</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-application.html">Functional Adventures in F# - Application State</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-types-with.html">Functional Adventures in F# - Types with member functions</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-getting-rid.html">Functional Adventures in F# - Getting rid of loops</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-getting-rid_22.html">Functional Adventures in F# - Getting rid of temp variables</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/04/functional-adventures-in-f.html">Functional Adventures in F# - The MailboxProcessor</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/05/functional-adventures-in-f-persisting.html">Functional Adventures in F# - Persisting Application State</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/05/functional-adventures-in-f-adding.html">Functional Adventures in F# - Adding Snapshot Persisting</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/06/functional-adventures-in-f-type-safe.html">Functional Adventures in F# - Type-safe identifiers</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/06/functional-adventures-in-f-event.html">Functional Adventures in F# - Event sourcing lessons learned</a><br />
<br />
<h2>
Storing all actions</h2>
The idea is pretty simple, we will store all actions sent to the <a href="https://dreamstatecoding.blogspot.com/2018/04/functional-adventures-in-f.html">AppHolder MailboxProcessor</a> and whenever we want to re-initiate the application state, we just load all the actions from storage and run them through the processor again and we should end up with the same application state.<br />
<br />
This has been described by other people, for example <a href="https://martinfowler.com/eaaDev/EventSourcing.html" target="_blank">Martin Fowler</a>, if you have the time then head over there and read his article about event sourcing.<br />
<br />
For this we will create a module called AppPersister. It will handle the actual storing and retrieving of the events from disk. So it will have side-effects and thus not be purely functional.... So lets just throw all those concepts out the door. But, this is a great opportunity to show some nice features of F# that will help write this kind of code a little more ... functional?<br />
For serialization I chose to use the json format, and serializer is the <a href="https://www.newtonsoft.com/json" target="_blank">JSON.NET library by Newtonsoft</a> that can be added to your project with NuGet.<br />
<br />
Some code for starters:<br />
<pre>module AppPersister =
open System
open System.Reflection
open System.IO
open Newtonsoft.Json
let private store = @".\store\"
</pre>
Basically we just create a new module that will handle the persisting of actions... Here we also define that the store should be a subdirectory for the application.<br />
<pre> let private createActionFilename (action:obj) =
let now = DateTime.UtcNow
let hourPath = now.ToString("yyyy-MM-dd HH")
let fullPath = Path.Combine(store, hourPath)
let di = new DirectoryInfo(fullPath)
di.Create()
let t = action.GetType()
let filename = now.ToString("yyyy-MM-dd hh_mm_ss_fffffff+") + now.Ticks.ToString() + "." + t.Name + ".action"
let fullFilename = Path.Combine(fullPath, filename)
fullFilename
</pre>
The createActionFilename function does just that, it generates a new unique filename for the action by combining todays date and time, throwing in the total number of ticks to ensure that we always have a fresh value and lastly adding the type of action and the extension '.action'. Here we also create the directory if it does not exist already for the current date and hour (UTC), the DirectoryInfo.Create method is safe to run on an already existing directory so we do no other checking ourselves.<br />
<pre> let PersistAction (action:obj) =
let fullFilename = createActionFilename action
let json = JsonConvert.SerializeObject(action)
File.WriteAllText(fullFilename, json)
()
</pre>
The PersisAction function handles the actual writing of the action to disk. We call createActionFilename to get the full filename and then use JsonConvert to serialize the action to a json string. Lastly we write the file with the nice File.WriteAllText method.<br />
<br />
Now that we can write the actions, lets write some code to read them from disk.<br />
<pre> let GetAllActions () =
let di = new DirectoryInfo(store)
let actions =
di.GetFiles("*.action", SearchOption.AllDirectories)
|> Seq.map (fun (fi:FileInfo) -> File.ReadAllText(fi.FullName), fi.Name)
|> Seq.map (fun x -> (getAction x))
|> Seq.toArray
actions
</pre>
<br />
<ul>
<li>Here we use the DirectoryInfo.GetFiles built in method to find all files with the .action extension in any subdirectory in the store path. The result is an array of FileInfo objects that we pipe to a </li>
<li>Seq.map where we return a Tuple containing the file contents and filename and pipe that tuple into</li>
<li>another Seq.map where we call getAction for all elements. This function will be tasked with deserializing the json to the correct type</li>
<li>Lastly we pipe the contents to Seq.toArray to make the result concrete. To my understanding is that the Seq constructs work a little like the IEnumerable and do lazy evaluation if you do not actually list it. </li>
</ul>
<pre> let private getAction (json:string, filename:string) =
let split = filename.Split('.')
let actionName = split.[1]
let actionNameWithNamespace = "dreamstatecoding.core.Actions+" + actionName
let t = Assembly.GetExecutingAssembly().GetType(actionNameWithNamespace)
JsonConvert.DeserializeObject(json, t)
</pre>
Lastly, the getAction function that is called from GetAllActions. Here we split the filename and pick out the part containing the name of the Action and then as the currently executing assembly to find the Type for that. Notice that we need to prefix the action name with the namespace name to make it work. In my solution I have all my actions in 1 module, so this works.<br />
<br />
<br />
<h2>
Rewriting AppHolder to work with persisted actions</h2>
Next step is to rewrite the AppHolder module from previous part to work with the AppPersister module.<br />
<br />
So what we want to do here is to separate actual real time Actions from Replay actions from the persisting, mainly so that they do not get persisted again (duplicated).<br />
<br />
So, lets put up a new discriminated union that defines what we want to do<br />
<pre> type Message =
| Replay of obj
| Action of obj
</pre>
<br />
So, either we want to execute a Replay object or execute an Action object.<br />
<pre> let private Processor = Agent.Start(fun inbox ->
let rec loop (s : AppliationState) =
async {
let! message = inbox.Receive()
let (action:obj) =
match message with
| Action a ->
AppPersister.PersistAction a
a
| Replay a -> a
let s' = s.HandleAction action
state <- s'
counter <- counter + 1
return! loop s'
}
loop AppliationState.Default)
</pre>
Now we rewrite our MailboxProcessor (Agent) to take a message instead of object directly. The first step is to pattern-match the received message to the type and get out the payload object.<br />
If we are handling an Action we want to persist it as well, so lets put that function call here as well. Otherwise no change here.<br />
<pre> let HandleAction (action:obj) =
Processor.Post (Action action)
</pre>
The old HandleAction code called Processor.Post with the action directly. Now we must state that it is an Action, and not a Replay.<br />
<pre> let private HandleReplayAction (action:obj) =
Processor.Post (Replay action)
</pre>
The same goes for the Replay execution, we just add a new function that executes actions as Replays<br />
<pre> let InitiateFromStore () =
AppPersister.GetAllActions()
|> Array.map (fun x -> (HandleReplayAction x))
|> ignore
()
</pre>
Lastly, a function to initialize the store, we pipe all the actions loaded from persistence to the HandleReplayAction and then pipe the results from that to <b>ignore</b>. This means that we are not really interested in the results from this function call, in the end we just return unit from the InitiateFromStore function.<br />
I put the call to this into my Program.cs file, it will load all the actions already executed from the store and execute them all as Replay actions.<br />
<br />
<h2>
Conclusions</h2>
In this part we have looked at how to persist the application state as a series of actions and then re-creating the application state when the application is restarted.<br />
For applications handling lots and lots of actions, we may want to limit the number of actions needed to recreate the up to date state.. So in the next part we will look at snapshots. My plan is to upload the code to git after the snapshot part has been added.<br />
<br />
All code provided as-is. This is copied from my own code-base, May need some additional programming to work. Use for whatever you want, how you want! If you find this helpful, please leave a comment, not required but appreciated! :)<br />
<br />
Hope this helps someone out there!Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1265125331765205173.post-56025801810310820252018-04-28T19:26:00.003+02:002020-03-10T12:55:44.852+01:00Functional Adventures in F# - The MailboxProcessor<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<img border="0" data-original-height="421" data-original-width="750" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxuc02LlL4nEunr-BU8tm-7MSNd3rnHT8TLOwL_dIESjGYqIe9uwUnAo24BwpOYlgXx7wPSf6DacWTLMbXWTAAWlY14pQrEu32S0iWp2BrSGdiczh5wXC_mf8nBOQc40HG_yohTOWpQzk/s1600/mailbox+processor.jpg" /></div>
<br />
In this post we will look at MailboxProcessor in F#.<br />
<br />
<b>This post is part of a series:</b><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-simple.html">Functional Adventures in F# - A simple planner</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-calling-f.html">Functional Adventures in F# - Calling F# from C#</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-using-map.html">Functional Adventures in F# - Using Map Collections</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-application.html">Functional Adventures in F# - Application State</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-types-with.html">Functional Adventures in F# - Types with member functions</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-getting-rid.html">Functional Adventures in F# - Getting rid of loops</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-getting-rid_22.html">Functional Adventures in F# - Getting rid of temp variables</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/04/functional-adventures-in-f.html">Functional Adventures in F# - The MailboxProcessor</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/05/functional-adventures-in-f-persisting.html">Functional Adventures in F# - Persisting Application State</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/05/functional-adventures-in-f-adding.html">Functional Adventures in F# - Adding Snapshot Persisting</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/06/functional-adventures-in-f-type-safe.html">Functional Adventures in F# - Type-safe identifiers</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/06/functional-adventures-in-f-event.html">Functional Adventures in F# - Event sourcing lessons learned</a><br />
<br />
<h2>
<b>MailboxProcessor</b></h2>
This continues with the code from Application State post.<br />
Mainly the GameState type<br />
<pre>and GameState =
{
PlayerStore:PlayerStore
UnitStore:UnitStore
}
member this.HandleAction (action:obj) (state:GameState) =
{
PlayerStore = state.PlayerStore.HandleAction action state.UserStore
UnitStore = state.UnitStore.HandleAction action state.AmmunitionStore
}
</pre>
<br />
<br />
My goal is to incorporate F# with C# in a nice way. And as described in the Application State post, the core application model and all actions that can be made in the application will be modeled in F#. But to prevent a multithreaded C# application to corrupt the state we need to serialize the commands that are processed.<br />
In C# I would have used a background <b>Thread </b>and a <b>Queue<T> </b>and written a locks to synchronize the reads and writes. Luckily in F#, we have all that nicely packaged in the built in <b>MailboxProcessor</b>.<br />
<br />
The first line redefines the MailboxProcessor to the term Agent instead, this seems to be something that a lot of people are doing, so lets stick to that for the time being.<br />
After that we define a F# static class, i.e. an abstract and sealed class with only static members. (this is what C# does under the hood).<br />
<br />
<pre>type Agent<'T> = MailboxProcessor<'T>
[<AbstractClass; Sealed>]
type GameHolder private () =
static let mutable state : GameState =
{
PlayerStore = { Players = Map.empty }
UnitStore = { Units = Map.empty }
}
static member State : GameState = state
static member private Processor = Agent.Start(fun inbox ->
let rec loop =
async {
let! action = inbox.Receive()
state <- state.HandleAction action state
return! loop
}
loop)
static member HandleAction (action:obj) =
GameHolder.Processor.Post action
</pre>
<br />
In addition we will be allowing for mutation here, something that the business logic in the F# module should be unaware of, but here, we are exposing the current state to the rest of the application so that it is easily accessible.<br />
<div>
I.e. C# we can call <b>GameHolder.State</b> and always get the latest state. It is exposed as immutable so there is no risk that other threads will write to it.</div>
<br />
After that we define the <b>MailboxProcessor<'T></b> or in this case the redefined Agent<'T> as a private static member of the class.<br />
What happens in the recursive part is a little iffy for me still. To my understanding the let! (with the exclamation mark) makes the inbox.Receive (that is also an async call) an synchronous call and stores its result in the action value.<br />
If anyone has detailed explanation of what is going on here, please feel free to comment as I was unable to find details of this seems just to be the way things are done.<br />
<br />
The HandleAction method calls the Post method on the MailboxProcessor and thus posts the action to the MailboxProcessor that in turn calls the HandleAction method of the State and mutates the exposed State value.<br />
<h2>
Update 2018-05-02, forcing serial access</h2>
Turns out the MailboxProcessor above does not work the way I thought... In my mind it serialized the processing but it did not. I.e. when multiple actions were sent to it in parallel, it corrupted the state variable.<br />
After looking at this for some time now, I finally had to post the question on stackoverflow.<br />
<a href="https://stackoverflow.com/questions/50135825/f-mailboxprocessor-limit-parallelism">https://stackoverflow.com/questions/50135825/f-mailboxprocessor-limit-parallelism</a><br />
<br />
Turns out the bad wolf in the drama was the static member. Changing the code to a module instead got the solution to work as expected.<br />
<br />
The end result is:<br />
<pre>module GameHolder =
type Agent<'T> = MailboxProcessor<'T>
let mutable private state = AppliationState.Default
let mutable private counter : int = 0
let GetCurrentState() = state
let GetProcessedActionsCounter() = counter
let private Processor = Agent.Start(fun inbox ->
let rec loop (s : AppliationState) =
async {
let! action = inbox.Receive()
let s' = s.HandleAction action
state <- s'
counter <- counter + 1
return! loop s'
}
loop AppliationState.Default)
let HandleAction (action:obj) =
Processor.Post action
</pre>
<br />
I can still get the current application state by calling a 'static' method from C#, in this case <b>GameHolder.GetCurrentState().</b><br />
So a small change thanks to stackoverflow and we still have a small but neat interface between our C# game/application and it model/business logic that is written in F#.<br />
<br />
<h2>
Finally</h2>
In the end. We have a GameHolder class that exposes State and HandleAction to the outside world. Whoever can query the state at anytime, but they are not allowed to change it other then through the HandleAction method.<br />
<br />
<i>All code provided as-is. This is copied from my own code-base, May need some additional programming to work. Use for whatever you want, how you want! If you find this helpful, please leave a comment or share a link, not required but appreciated! :)</i><br />
<br />
Hope this helps someone out there!Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-1265125331765205173.post-65000199259874737092018-03-22T13:37:00.000+01:002020-03-10T12:55:33.282+01:00Functional Adventures in F# - Getting rid of temp variables<div class="separator" style="clear: both; text-align: center;">
<img border="0" data-original-height="421" data-original-width="750" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjB_d8Z-ZvAnJY-60HuVgh2PV6iDrhvkPuiFATiZ5DQkvqxhS8FbmLVNqRHPzTUD6p8FPInSyKb91i-i_iwfuSOSp2OrNViD8JbW3oDix8LBUa3xsYvePimuJ_FrK2VgUAoMQmbNJFh4fE/s1600/getting+rid+of+temp+variables.jpg" /></div>
<br />
This time we will look at how to get rid of temporary variables when updating an object in multiple steps.<br />
<br />
<b>This post is part of a series:</b><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-simple.html">Functional Adventures in F# - A simple planner</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-calling-f.html">Functional Adventures in F# - Calling F# from C#</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-using-map.html">Functional Adventures in F# - Using Map Collections</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-application.html">Functional Adventures in F# - Application State</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-types-with.html">Functional Adventures in F# - Types with member functions</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-getting-rid.html">Functional Adventures in F# - Getting rid of loops</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-getting-rid_22.html">Functional Adventures in F# - Getting rid of temp variables</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/04/functional-adventures-in-f.html">Functional Adventures in F# - The MailboxProcessor</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/05/functional-adventures-in-f-persisting.html">Functional Adventures in F# - Persisting Application State</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/05/functional-adventures-in-f-adding.html">Functional Adventures in F# - Adding Snapshot Persisting</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/06/functional-adventures-in-f-type-safe.html">Functional Adventures in F# - Type-safe identifiers</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/06/functional-adventures-in-f-event.html">Functional Adventures in F# - Event sourcing lessons learned</a><br />
<br />
In my game that I am trying to write with F# (at least the core model) I have some functions that look like the following<br />
<pre>static member HandleTick (state:UnitStore) (action:Tick) =
let queueUpdatedState = UnitStore.handleTickBuildQueues state action
let unitsUpdatedState = UnitStore.handleTickUnitUpdates queueUpdatedState action
unitsUpdatedState
</pre>
A function that takes a state and an <a href="http://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-application.html">action </a>and in turn it uses other functions to update that state with the help of the <a href="http://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-application.html">action</a>.<br />
I don't know, but I grew tired of naming temporary variables after a while and started googling for a better solution. Turns out there is one. By using the forward-pipe operator '|>' we can take the output of one function and send it as input to the next function.<br />
<br />
<pre>static member HandleTick (state:UnitStore) (action:Tick) =
UnitStore.handleTickBuildQueues action state
|> UnitStore.handleTickUnitUpdates action
</pre>
To make this work, the order of parameters need to be switched so that <b>Action</b> is the first argument followed by the <b>State</b>.<br />
Turns out I have to refactor all the functions in my <a href="http://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-application.html">Stores </a>to take the action first and state as second argument to get this working, but I guess that is a small price to pay for cleaner code.<br />
<br />
Looking at the assembly in ILSpy gives us that in the background there will be temporary variables passed around, but our code is clean of them.<br />
<pre>public static UnitStore HandleTick(Actions.Tick action, UnitStore state)
{
UnitStore unitStore = UnitStore.handleTickBuildQueues(action, state);
UnitStore state2 = unitStore;
return UnitStore.handleTickUnitUpdates(action, state2);
}
</pre>
<br />
All code provided as-is. This is copied from my own code-base, May need some additional programming to work. Use for whatever you want, how you want! If you find this helpful, please leave a comment, not required but appreciated! :)<br />
<br />
Hope this helps someone out there!Unknownnoreply@blogger.com7tag:blogger.com,1999:blog-1265125331765205173.post-26636463430407487422018-03-21T23:44:00.000+01:002020-03-10T12:55:27.808+01:00Functional Adventures in F# - Getting rid of loops<div class="separator" style="clear: both; text-align: center;">
<img border="0" data-original-height="421" data-original-width="750" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvalmiyhTnj2404kQHqqToG9_BqEOqAAvqmxV4TLTfDTK-vn9BJzLRw38NqzcpbjbxlTih9gfCS2K-hHMLXnHzo1gf8fGgmHluBtQjTBQwiLZl8HL7IJqzATaV3d3wuJytK5M8kDRD3m4/s1600/getting+rid+of+loops.jpg" /></div>
<br />
Solving problems without loops.....<br />
<br />
<b>This post is part of a series:</b><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-simple.html">Functional Adventures in F# - A simple planner</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-calling-f.html">Functional Adventures in F# - Calling F# from C#</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-using-map.html">Functional Adventures in F# - Using Map Collections</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-application.html">Functional Adventures in F# - Application State</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-types-with.html">Functional Adventures in F# - Types with member functions</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-getting-rid.html">Functional Adventures in F# - Getting rid of loops</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-getting-rid_22.html">Functional Adventures in F# - Getting rid of temp variables</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/04/functional-adventures-in-f.html">Functional Adventures in F# - The MailboxProcessor</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/05/functional-adventures-in-f-persisting.html">Functional Adventures in F# - Persisting Application State</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/05/functional-adventures-in-f-adding.html">Functional Adventures in F# - Adding Snapshot Persisting</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/06/functional-adventures-in-f-type-safe.html">Functional Adventures in F# - Type-safe identifiers</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/06/functional-adventures-in-f-event.html">Functional Adventures in F# - Event sourcing lessons learned</a><br />
<br />
This time lets look at a real issue when coming from an imperative language and trying functional programming.<br />
The example problem (that I crashed into when rewriting some game logic in F#) is that of spawning new Ships in a space game. We do not want to spawn 2 ships on top of each other, so we generate the default spawning coordinate and then test if it is safe to use, if not we move the ship a bit and try again....<br />
<br />
How I solved it in C#..<br />
<pre>private Ship FindClosestFreeCoordinate(ImmutableList<Fleet> state, Ship newShip)
{
var shipsWithinSafetyDistance = ShipsWithinSafetyDistance(state, newShip);
while (shipsWithinSafetyDistance.Any())
{
var newCoordinates = newShip.Coordinates.Position.Add(Vector3.UnitXVector);
newShip = newShip.Modify(coordinates: newShip.Coordinates.Modify(position: newCoordinates));
shipsWithinSafetyDistance = ShipsWithinSafetyDistance(state, newShip);
}
return newShip;
}
private List<Ship> ShipsWithinSafetyDistance(ImmutableList<Fleet> state, Ship newShip)
{
return (from fleet in state
from
ship in fleet.Ships
where
ship.Distance(newShip) < 5
select ship).ToList();
}
</pre>
<br />
Translating the ShipsWithinSafetyDistance function is no problem. We just use the Map.filter function...<br />
<pre>static member private shipsWithinSafetyDistance (unit:Unit) (state:UnitStore) =
Map.filter (fun key value -> unit.distanceToUnit value < 5.0) state.Units
</pre>
Ah, yes.. I switched from a ImmutableList in C# to a Map in F#, just to keep things interesting (and to get faster Key lookups)<br />
<br />
<br />
So, the tricky part here is the while loop. Most loops can be rewritten with Map/List functions like map, filter and fold etc... But this time I don't see how to use them as I don't have a Collection of any sort here so my brain keeps yelling "Write a loooooop", as that is the way I have solved this kind of problems for the past 20+ years... So...<br />
How should we do it in F#??? We have some other constructs to use that fit the functional idea better.<br />
<br />
<pre>static member private findClosestFreeCoordinate (unit:Unit) (state:UnitStore) =
let rec findClosestFreeCoordinateRecursive (unit:Unit) (state:UnitStore) =
let shipsWithinSafetyDistance = shipsWithinSafetyDistance unit state
match shipsWithinSafetyDistance with
| a when a.IsEmpty -> unit
| _ -> let newUnit = { unit with Coordinates = unit.Coordinates + Vector3.UnitX }
findClosestFreeCoordinateRecursive newUnit state
findClosestFreeCoordinateRecursive unit state
</pre>
<b>Recursion!</b><br />
At least for this problem, it seems to be a good option. Here we define a function, <b>findClosestFreeCoordinateRecursive </b>with the <b>rec </b>keyword to let the compiler know that it will be called recursively. In the function body we match the result list with IsEmpty and return the input value or else call the recursive function with a new copy of the unit with new coordinates.<br />
<br />
Call stack.. Is there a risk for stack overflow with this?<br />
Lets open the dll output with ILSpy to check what actually goes on behind the scenes<br />
<div class="separator" style="clear: both; text-align: center;">
<img alt="ILSpy of F# Recursive Function" border="0" data-original-height="419" data-original-width="750" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgP1F0OtF7HLeYZliX7myb8T5jGWv2VaXS4SYR-AV0ZSaNZWHfJr5QSWi2Hq88XYX0ZvAr0gE00uO5zIRa7UEjloc0BBQgWTAENvtUfCRSjjKu54oyf6zVkhO7KxP7l1DEJowChyphenhyphentQfiRc/s1600/ilspy+recursive.jpg" title="ILSpy of F# Recursive Function" /></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
Turns out, that the current F# compiler in the background uses a while loop. The key here is that we do not, instead we define a short and concise function where we state what it is that we want done, how it is solved behind the scene in detail is not up to us. At some point, there is always someone that needs to write the ifs and loops, but lets keep them away from the application code that we write.<br />
<br />
So there, lets move the last shipsWithinSafetyDistance to inner scope of our function and we are set<br />
<pre>static member private findClosestFreeCoordinate (unit:Unit) (state:UnitStore) =
let shipsWithinSafetyDistance (unit:Unit) (state:UnitStore) =
Map.filter (fun _ value -> unit.distanceToUnit value < 50.0) state.Units
let rec findClosestFreeCoordinateRecursive (unit:Unit) (state:UnitStore) =
let shipsWithinSafetyDistance = shipsWithinSafetyDistance unit state
match shipsWithinSafetyDistance with
| a when a.IsEmpty -> unit
| _ -> let newUnit = { unit with Coordinates = unit.Coordinates + Vector3.UnitX }
findClosestFreeCoordinateRecursive newUnit state
findClosestFreeCoordinateRecursive unit state
</pre>
<br />
All code provided as-is. This is copied from my own code-base, May need some additional programming to work. Use for whatever you want, how you want! If you find this helpful, please leave a comment, not required but appreciated! :)<br />
<br />
Hope this helps someone out there!<br />
<div>
<br /></div>
<br />Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-1265125331765205173.post-24392898218893965992018-03-16T20:57:00.001+01:002020-03-10T12:55:22.666+01:00Functional Adventures in F# - Types with member functions<div class="separator" style="clear: both; text-align: center;">
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-types-with.html"><img border="0" data-original-height="421" data-original-width="750" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwI-BrEM1e1aVoXjDVwY7X7KgEYq-BLN7OI1WCV5a9xtRkJu_sYZ1udEIW2bpXBC4QlLlyiXbahptkfXcRhP-QcMf4g2RHPBBPZlllRYzqZxkGPftzexdhjQneoxmTJpBc23J_tjneDYM/s1600/types+with+member+functions.jpg" /></a></div>
Lets look at how to structure functions into the types that they are linked to, this helps with keeping the code base clean.<br />
<br />
<b>This post is part of a series:</b><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-simple.html">Functional Adventures in F# - A simple planner</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-calling-f.html">Functional Adventures in F# - Calling F# from C#</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-using-map.html">Functional Adventures in F# - Using Map Collections</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-application.html">Functional Adventures in F# - Application State</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-types-with.html">Functional Adventures in F# - Types with member functions</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-getting-rid.html">Functional Adventures in F# - Getting rid of loops</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-getting-rid_22.html">Functional Adventures in F# - Getting rid of temp variables</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/04/functional-adventures-in-f.html">Functional Adventures in F# - The MailboxProcessor</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/05/functional-adventures-in-f-persisting.html">Functional Adventures in F# - Persisting Application State</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/05/functional-adventures-in-f-adding.html">Functional Adventures in F# - Adding Snapshot Persisting</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/06/functional-adventures-in-f-type-safe.html">Functional Adventures in F# - Type-safe identifiers</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/06/functional-adventures-in-f-event.html">Functional Adventures in F# - Event sourcing lessons learned</a><br />
<br />
<br />
I started converting my small but handy 3D math library to F# and very quickly I ran into a problem. Not that unexpected as I am a beginner with F#.<br />
So say that you have some types:<br />
<pre>type Vector3 =
{
X:float
Y:float
Z:float
}
type Vector4 =
{
X:float
Y:float
Z:float
W:float
}
</pre>
That in the end will have quite similar functionality like .. for example Add, Divide etc. With the knowledge that I have so far of F# I ended up with<br />
<pre>let addVector3 (value1:Vector3) (value2:Vector3) =
{
X = value1.X + value2.X
Y = value1.Y + value2.Y
Z = value1.Z + value2.Z
}
let addVector4 (value1:Vector4) (value2:Vector4) =
{
X = value1.X + value2.X
Y = value1.Y + value2.Y
Z = value1.Z + value2.Z
W = value1.W + value2.W
}
</pre>
I quickly thought that there must be a cleaner way to write this. I like tidy code, neat code.. not code that just looks bad and will turn into a maintenance hell even before it is shipped.<br />
Luckily it turns out you can define functions as members of types. So the above 2 functions would look like:<br />
<pre>type Vector3 =
{
X:float
Y:float
Z:float
}
member this.add (value2:Vector3) =
{
X = this.X + value2.X
Y = this.Y + value2.Y
Z = this.Z + value2.Z
}
type Vector4 =
{
X:float
Y:float
Z:float
W:float
}
member this.add (value2:Vector4) =
{
X = this.X + value2.X
Y = this.Y + value2.Y
Z = this.Z + value2.Z
W = this.W + value2.W
}
</pre>
Here, both are called just add, and they can be invoked directly on the objects.<br />
<pre>let value1 = { X = 1.0; Y = 1.0; Z = 1.0 }
let value2 = { X = 2.0; Y = 2.0; Z = 2.0 }
let added = value1.add value2
</pre>
A little cumbersome syntax if you want to do more complex calculations. So lets look at operator overloading in F# to so that we can get nice arithmetic operators into play for our new types<br />
<pre>type Vector3 =
{
X:float
Y:float
Z:float
}
static member (+) (value1:Vector3, value2:Vector3) =
{
X = value1.X + value2.X
Y = value1.Y + value2.Y
Z = value1.Z + value2.Z
}
static member maxValue = { X = Microsoft.FSharp.Core.float.MaxValue; Y = Microsoft.FSharp.Core.float.MaxValue; Z = Microsoft.FSharp.Core.float.MaxValue; }
member this.add (value2:Vector3) = this + value2
</pre>
This lets us write something like this instead:
<br />
<pre>let added = value1 + value2
</pre>
Also note the static member maxValue that is a static function that is invoked by Vector3.maxValue, in this case it just returns the max vector but it can be any function.<br />
<br />
So there.<br />
<br />
<i><b>Update</b>: evidently static members should start with capital letter according to <a href="http://fsharp.org/specs/component-design-guidelines/" target="_blank">design guide-lines</a>. Makes sense as they are easier to spot.</i><br />
<br />
All code provided as-is. This is copied from my own code-base, May need some additional programming to work. Use for whatever you want, how you want! If you find this helpful, please leave a comment, not required but appreciated! :)<br />
<br />
Hope this helps someone out there!<br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1265125331765205173.post-8716214545493257312018-03-15T20:11:00.001+01:002020-03-10T12:55:15.156+01:00Functional Adventures in F# - Application State<div class="separator" style="clear: both; text-align: center;">
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-application.html"><img border="0" data-original-height="421" data-original-width="750" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglPDUB-hEEuvrcbDEgCYX5oG1T96iNF3QYkdKuULGHzvit3s1OtKw3yKEcTtf7PDlPAUHv3VDAkyQ8wnkmDnGQcop0Ld38XpJKkDLS8zykc3wtV-n8ZO41g36RiVCzmu-Ibes1Fq7MV8s/s1600/application+state.jpg" /></a></div>
<br />
In this article we will go through how to handle complex application state in F#. This will in practice be a rewrite of '<a href="http://dreamstatecoding.blogspot.com/2017/10/functional-adventures-in-net-c-part-2.html">Functional Adventures in C# - Application State</a>'. So I will probably skip a lot of the details and focus on the F# implementation.<br />
<br />
<b>This post is part of a series:</b><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-simple.html">Functional Adventures in F# - A simple planner</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-calling-f.html">Functional Adventures in F# - Calling F# from C#</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-using-map.html">Functional Adventures in F# - Using Map Collections</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-application.html">Functional Adventures in F# - Application State</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-types-with.html">Functional Adventures in F# - Types with member functions</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-getting-rid.html">Functional Adventures in F# - Getting rid of loops</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-getting-rid_22.html">Functional Adventures in F# - Getting rid of temp variables</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/04/functional-adventures-in-f.html">Functional Adventures in F# - The MailboxProcessor</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/05/functional-adventures-in-f-persisting.html">Functional Adventures in F# - Persisting Application State</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/05/functional-adventures-in-f-adding.html">Functional Adventures in F# - Adding Snapshot Persisting</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/06/functional-adventures-in-f-type-safe.html">Functional Adventures in F# - Type-safe identifiers</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/06/functional-adventures-in-f-event.html">Functional Adventures in F# - Event sourcing lessons learned</a><br />
<h2>
Overview</h2>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><img border="0" data-original-height="422" data-original-width="750" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuJBehXLkn-jjFWQXW2MDjzsf-Grh8XqJwgKcLnqUC8sTkmrVc8DTGPNk_eILTVRFGrx7xVnENFwEyE1juWpBV1cmLWJg_JucWKNLbnbeKI0dtwfI8K3rZb9b7AfaYi9aEdwbw97PaKdE/s1600/functional+adventures+in+net+c+part+2+application+state+stores.jpg" style="margin-left: auto; margin-right: auto;" /></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Illustration of Application State, different Stores and their model objects. For a lot of illustrations go read the C# article!</td></tr>
</tbody></table>
Lets be real, nobody read the <a href="http://dreamstatecoding.blogspot.com/2017/10/functional-adventures-in-net-c-part-2.html">C# version first.</a> So I'll paste the overview here.<br />
<blockquote class="tr_bq">
<span style="background-color: white; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 14.85px;"><i>At any given point in time, the whole application state is stored in a class named Application State, it consists of different Stores and they in turn consist of the object model for each store. I.e. Fleet Store might contain Fleets that consists of Ships. All updates to the model are routed to the store in the form of Actions. The application state is immutable, meaning that any object that you get a reference to will never mutate into something else (see previous post in this series on Immutable objects)</i></span></blockquote>
So. from the text above we need to define <b>Actions</b>, <b>Application State</b>, and <b>Stores</b> and we should be set to go.<br />
<h2>
Actions</h2>
<div>
Actions will be implemented as basic record types. There is no need for anything else fancy. An action should contain all information that is needed to create a new application state.</div>
<blockquote class="tr_bq">
<i><b>newApplicationState = currentApplicationState + action</b></i></blockquote>
<div>
The code for this part looks like the following</div>
<pre>module Actions =
type InsertCashToPlayerAccount = { Player:GameModel.PlayerId; Amount:GameModel.Cash }
type Tick = { Time:float; Delta:float }
</pre>
We defined 2 actions. One that puts money into the players account and the other lets us update each store before rendering a new frame in a game.<br />
<br />
<h2>
Application State</h2>
Next up, we will look at the Application State definition, or in this example the GameState definition<br />
<pre>module GameState =
type GameState =
{
PlayerStore:PlayerStore
UnitStore:UnitStore
}
</pre>
Here we just define that <b>GameState</b> is a record type that contains 2 stores, the <b>PlayerStore</b> and the <b>UnitStore</b>. Here we will also be adding a way to handle actions, so lets continue with the <b>GameState</b> definition<br />
<pre>
static member handleAction (state:GameState) (action:obj) =
{
PlayerStore = PlayerStore.handleAction state.PlayerStore action
UnitStore = UnitStore.handleAction state.UnitStore action
}
</pre>
Here we add a static member function to the <b>handleAction</b> type (that can be called as: '<i>GameState.handleAction state action</i>'). We have defined the types here, the state is a <b>GameState</b> and the action is typed to <b>obj</b>, meaning that we can send in any type into this function and it will work. I.e. when we define new actions, we don't need to change anything here. Only if we add a new <b>Store</b>, then we need to add it here obviously.<br />
Also, worth noting is that the action is in turn sent to all <b>Store</b> handlers together with the part of the state that is handled by that <b>Store</b>. Meaning that we can define an action, that is handled by multiple stores. For example the Tick action above.
<br />
So basically the handleAction function just builds a new Application State by calling each store and telling them to handle their parts.<br />
<br />
<h2>
Stores</h2>
OK, so whats so special about the stores? Nothing really, the Application State is practically a store in itself,<br />
<pre>module PlayerStore =
type PlayerStore =
{
Players: Map<PlayerId, Player>
CurrentTime: float
}
static member handleInsertCashToPlayerAccount (state:PlayerStore) (action:InsertCashToPlayerAccount) =
let player = state.Players.[action.Player]
let newPlayer = { player with Cash = player.Cash + action.Amount }
{ state with Players = state.Players.Add(player.Id, newPlayer) }
static member handleTick (state:PlayerStore) (action:Tick) =
{ state with CurrentTime = action.Time }
static member handleAction (state:PlayerStore) (action:obj) =
match action with
| :? InsertCashToPlayerAccount as a -> PlayerStore.handleInsertCashToPlayerAccount state a
| :? Tick as a -> PlayerStore.handleTick state a
| _ -> state
</pre>
<b>PlayerStore</b> is a record type, just as the <b>GameState</b> type, with a static member <b>handleAction</b> function that has a little different implementation. The key here is the pattern matching on the action, we use the type of the action to determine what handler function should be called to perform whatever it is that the action needs done. As a last state, we have the wild card pattern '_' that returns the old state as it was sent in. I.e. if this <b>actionHandler</b> can't handle the action, nothing is done.<br />
Also notable in the <b>handleInsertCashToPlayerAccount</b> function, the new state is built by taking the current state and applying the action. In this example, finding the player object and constructing a new player object with the added cash in it.<br />
<br />
Lastly, lets look at the <b>UnitStore</b> so that we have all the code for our example<br />
<pre>module UnitStore =
type UnitStore =
{
Units: Map<GameObjectId, Unit>
CurrentGameObjectId: GameObjectId
CurrentTime: float
}
static member handleTick (state:UnitStore) (action:Tick) =
{ state with CurrentTime = action.Time }
static member handleAction (state:UnitStore) (action:obj) =
match action with
| :? Tick as a -> UnitStore.handleTick state a
| _ -> state
</pre>
Same thing here, the handleAction function takes the UnitStore and the action and then matches an action handler function if one exists to create a new state, otherwise it will just hand back the original state.<br />
<br />
Tests<br />
<pre>[<TestClass>]
type StoreTests () =
member this.createDefaultStore =
{
PlayerStore =
{
Players = Map.empty.Add(1, { Id = 1; Name = "Player1"; Cash = 0; CurrentSelection = [] })
CurrentTime = 0.0
}
UnitStore =
{
Units = Map.empty
CurrentGameObjectId = 0
CurrentTime = 0.0
}
}
</pre>
For starters, we define a function that creates the initial <b>GameState</b> that will be used by all of our tests.<br />
<pre> [<TestMethod>]
member this.StoreTests_GameState_UnknownType () =
let originalState = this.createDefaultStore
let action = 1
let newState = GameState.handleAction originalState action
Assert.AreEqual(originalState, newState)
</pre>
First test, just check that if we send in an unknown action, we get back the original state object, nothing changed, the exact same object.<br />
<pre> [<TestMethod>]
member this.StoreTests_GameState_UpdatePlayerStore () =
let originalState = this.createDefaultStore
let action = { Player = 1; Amount = 10 }
let newState = GameState.handleAction originalState action
Assert.AreNotEqual(originalState, newState)
Assert.AreEqual(originalState.UnitStore, newState.UnitStore)
Assert.AreEqual(10, newState.PlayerStore.Players.[1].Cash)
</pre>
Secondly we test that an action that should update 1 store, does that, but leaves the other stores unchanged.<br />
<pre> [<TestMethod>]
member this.StoreTests_GameState_UpdateMultipleStores () =
let originalState = this.createDefaultStore
let action = { Time = 22.0; Delta = 0.015 }
let newState = GameState.handleAction originalState action
Assert.AreNotEqual(originalState, newState)
Assert.AreEqual(22.0, newState.PlayerStore.CurrentTime)
Assert.AreEqual(22.0, newState.UnitStore.CurrentTime)
</pre>
The last test just verifies that an action can be handled by multiple <b>Stores</b>.<br />
<br />
<h2>
Finally</h2>
There are probably a lot of things that could be written in a better way, I am still learning F# and finding new ways to do things daily. Overall I find that this language has nice constructs for many of the things I tried to do with C# when I tried functional constructs there. A lot less plumbing here as the language has built in support for many of the things, lets one focus on actually writing functionality instead of plumbing code. I am glad that I tried this out : )<br />
<br />
All code provided as-is. This is copied from my own code-base, May need some additional programming to work. Use for whatever you want, how you want! If you find this helpful, please leave a comment, not required but appreciated! :)<br />
<br />
Hope this helps someone out there!Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1265125331765205173.post-64185761054134537092018-03-13T13:07:00.001+01:002020-03-10T12:54:43.923+01:00Functional Adventures in F# - Using Map Collections<div class="separator" style="clear: both; text-align: center;">
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-using-map.html"><img border="0" data-original-height="421" data-original-width="750" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhU41jvaceiMNUplpX9JBxgCU8VpDpidWJ-Dn9zSfbR5ignudsE7HXbKUQArs4SUq1zHqHmB57uADavfPMke9aLF7VHbLReEoZXV7i98hjlWtUBHldNK3lrjX_uiKI7No0f5chcX3kVm44/s1600/Using+Map+Collections.jpg" /></a></div>
<br />
This time we will look at how we can manipulate Map collections to store data.<br />
<br />
<b>This post is part of a series:</b><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-simple.html">Functional Adventures in F# - A simple planner</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-calling-f.html">Functional Adventures in F# - Calling F# from C#</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-using-map.html">Functional Adventures in F# - Using Map Collections</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-application.html">Functional Adventures in F# - Application State</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-types-with.html">Functional Adventures in F# - Types with member functions</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-getting-rid.html">Functional Adventures in F# - Getting rid of loops</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-getting-rid_22.html">Functional Adventures in F# - Getting rid of temp variables</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/04/functional-adventures-in-f.html">Functional Adventures in F# - The MailboxProcessor</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/05/functional-adventures-in-f-persisting.html">Functional Adventures in F# - Persisting Application State</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/05/functional-adventures-in-f-adding.html">Functional Adventures in F# - Adding Snapshot Persisting</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/06/functional-adventures-in-f-type-safe.html">Functional Adventures in F# - Type-safe identifiers</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/06/functional-adventures-in-f-event.html">Functional Adventures in F# - Event sourcing lessons learned</a><br />
<br />
I am no expert in F#, writing these posts is a way for me to learn and hopefully they can help someone else as well.<br />
<br />
<h2>
Graph of symbols</h2>
OK, so I want to create a symbol <a href="https://en.wikipedia.org/wiki/Graph_(discrete_mathematics)" target="_blank">graph</a> (influenced by some ideas in the book '<a href="https://en.wikipedia.org/wiki/G%C3%B6del,_Escher,_Bach" target="_blank">Gödel, Escher, Bach: An Eternal Golden Braid</a>', a book I really recommend everyone to read)<br />
This is just a very naive implementation but it raised some issues when dealing with F# in general.<br />
Basic concept is that you have a bunch of symbols and each time they are triggered together with another symbol you either add an edge or increase the edges weight. And when 2 symbols are totally interlinked, they may become a new symbol of their own. But in this example I will just focus on the graph bit.<br />
<h2>
Defining types with and keyword</h2>
For example: In F#, everything that you use need to be defined before you use them. Meaning that if you have type X that references type Y, and then type Y reference type X.. You have a problem.<br />
<pre>type X = { name:string; hits:int; outgoingEdges:Y}
type Y = { target:X; hits:int; }
</pre>
This would result in a "The type 'Y' is not defined." error. To solve it, we can change the second type definition to use the keyword and instead of type.<br />
<pre>type X = { name:string; hits:int; outgoingEdges:Y}
and Y = { target:X; hits:int; }
</pre>
<br />
Lets start with defining some types.<br />
<pre>module Symbolism =
type Edge = { targetName:string; hits:int; }
type Symbol = { name:string; hits:int; outgoingEdges:Edges}
and Edges = Map<string, Edge>
type Symbols = Map<string, Symbol>
</pre>
So here we see the usage of the and keyword as Symbol forward references Edges.<br />
<br />
<h2>
Using Map Collections</h2>
<div>
As you can see above, we have defined Edges and Symbols to be of the type Map, basically Map works like a Dictionary in C#, there are probably differences (other then the immutability part), but for my purposes I like to think that they are about the same. They both store objects as Key/Value pairs.</div>
<div>
<br /></div>
<div>
So, our first function will be getSymbol that takes a Symbols collection and the name of the symbol to get. Here I want to return the symbol from the Map if it exists, otherwise return a new empty symbol that has never been seen before. For this we will use pattern matching mechanism of F#, the task is quite trivial and thus a straight forward place to figure out how pattern matching works.</div>
<pre>let getSymbol (symbols:Symbols) (key:string) =
match symbols.ContainsKey key with
| true -> symbols.[key]
| _ -> { name = key; hits = 0; outgoingEdges = Map.empty }
</pre>
We start by checking if they Symbols Map contains the key with the <b>match [expression] with</b> part.<br />
The next line we define what happens if the result is true. We return the object that is in the Map, notice the dot (.) before the indexer. In C# you would access a dictionary as '<i>symbols[key]</i>' but in F# you need the extra dot.<br />
The second pattern line means, anything else.... So in this case it would be if the result is false we return a brand new record. The <b>outgoingEdges </b>is of the type <b>Edges </b>that is a <b>Map<string, Edge></b>. I spent some time trying to initialize it with <i>Edges.empty</i> until I figured out that it is the <b>Map.empty</b> that should be used to initialize an empty map of any type.<br />
<br />
Next, we want to add or update a value in the Map.<br />
<pre>let addEdgeToSymbol (symbol:Symbol) (target:Symbol) =
let edge = getEdge symbol target
let weightedEdge = increaseEdgeWeigth edge
let updatedSymbol:Symbol = { symbol with outgoingEdges = symbol.outgoingEdges.Add(target.name, weightedEdge) }
updatedSymbol
</pre>
This took me a while as well. Trying to google how to update a value in a Map collection. Evidently it is built into the Add function.<br />
If the key does not exist in the Map: a new Map with the key/value pair added to it is returned<br />
If the key exists already in the Map: a new Map with the value in the key location updated is returned.<br />
Pretty neat to not have to bloat the code with all the checks just to add or update, just call the Add function.<br />
Here also, we want to update one field in the symbol record. We could define a new record and manually copy all the fields but that is just code debt waiting to blow. Instead there is a nice way to do this with the following line.<br />
<pre>{ symbol with outgoingEdges = symbol.outgoingEdges.Add(target.name, weightedEdge) }
</pre>
Here we say, that we want a new record based on the values in the record 'symbol' but with the following things updated. In this case the outgoingEdges field.<br />
<br />
<h2>
Full source code</h2>
<pre>module Symbolism =
type Edge = { targetName:string; hits:int; }
type Symbol = { name:string; hits:int; outgoingEdges:Edges}
and Edges = Map<string, Edge>
type Symbols = Map<string, Symbol>
let getSymbol (symbols:Symbols) (key:string) =
match symbols.ContainsKey key with
| true -> symbols.[key]
| _ -> { name = key; hits = 0; outgoingEdges = Map.empty }
let getEdge (symbol:Symbol) (target:Symbol) =
match symbol.outgoingEdges.ContainsKey target.name with
| true -> symbol.outgoingEdges.[target.name]
| _ -> { targetName = target.name; hits = 0; }
let increasSymboleWeigth symbol:Symbol =
let updatedSymbol:Symbol = { symbol with hits = symbol.hits + 1 }
updatedSymbol
let increaseEdgeWeigth edge:Edge =
let updatedEdge:Edge = { edge with hits = edge.hits + 1 }
updatedEdge
let addEdgeToSymbol (symbol:Symbol) (target:Symbol) =
let edge = getEdge symbol target
let weightedEdge = increaseEdgeWeigth edge
let updatedSymbol:Symbol = { symbol with outgoingEdges = symbol.outgoingEdges.Add(target.name, weightedEdge) }
updatedSymbol
let addEdge (symbols:Symbols) (from:string) (target:string) =
let symbol = getSymbol symbols from
let targetSymbol = getSymbol symbols target
let edgedSymbol = addEdgeToSymbol symbol targetSymbol
let weightedSymbol = increasSymboleWeigth edgedSymbol
let weightedTargetSymbol = increasSymboleWeigth targetSymbol
symbols
.Add(from, weightedSymbol)
.Add(target, weightedTargetSymbol)
</pre>
<br />
<h2>
Unit tests</h2>
<pre>[<TestClass>]
type SymbolismTest () =
[<TestMethod>]
member this.Symbolism_getSymbol_NoExistingSymbols () =
let target : Symbols = Map.empty
let actual = getSymbol target "ewan mcgregor"
Assert.AreEqual("ewan mcgregor", actual.name)
Assert.AreEqual(0, actual.outgoingEdges.Count)
[<TestMethod>]
member this.Symbolism_getSymbol_ExistingSymbol () =
let target : Symbols = Map.empty.Add("ewan mcgregor", { name = "test item"; hits = 0; outgoingEdges = Map.empty })
let actual = getSymbol target "ewan mcgregor"
Assert.AreEqual("test item", actual.name)
Assert.AreEqual(0, actual.outgoingEdges.Count)
[<TestMethod>]
member this.Symbolism_addEdgeToSymbol () =
let from = { name = "daisy ridley"; hits = 0; outgoingEdges = Map.empty }
let target = { name = "star wars"; hits = 0; outgoingEdges = Map.empty }
let actual = addEdgeToSymbol from target
Assert.AreEqual("daisy ridley", actual.name)
Assert.AreEqual(1, actual.outgoingEdges.Count)
Assert.IsTrue(actual.outgoingEdges.ContainsKey("star wars"))
Assert.AreEqual(1, actual.outgoingEdges.["star wars"].hits)
[<TestMethod>]
member this.Symbolism_addEdge_NoExistingSymbols () =
let target : Symbols = Map.empty
let symbols = addEdge target "ewan mcgregor" "star wars"
let actualewan = getSymbol symbols "ewan mcgregor"
let actualStarWars = getSymbol symbols "star wars"
Assert.AreEqual("ewan mcgregor", actualewan.name)
Assert.AreEqual(1, actualewan.hits)
Assert.AreEqual(1, actualewan.outgoingEdges.Count)
Assert.AreEqual("star wars", actualStarWars.name)
Assert.AreEqual(1, actualStarWars.hits)
Assert.AreEqual(0, actualStarWars.outgoingEdges.Count)
Assert.AreEqual(2, symbols.Count)
</pre>
<br />
Here in the <b>Symbolism_getSymbol_ExistingSymbol </b>test we can see how to initialize a Map with a starting key value. I.e. by adding an item to an empty Map.<br />
<br />
<br />
<br />
<h2>
Merging 2 Map collections</h2>
<i>Added 2018-03-21, did not want to create a new post for this.</i><br />
At some point you may come across a problem that needs to be solved by merging 2 different Map collections that have the same type if Key and Value. To use this, we will use Map.fold to create a new Map collection that has the contents of both input Maps<br />
<pre>let newUnits = Map.fold (fun acc key value -> Map.add key value acc) state.Units builtUnits
</pre>
<br />
<br />
<br />
<br />
<b>So there it is. We have gone through how to</b><br />
<ul>
<li>Check if a key exists in a Map</li>
<li>Retrieve the value stored in the Map for a particular key</li>
<li>Add values to a Map</li>
<li>Update values in a Map</li>
<li>Initialize an empty Map</li>
<li>Initialize a Map with key/value pairs from the start</li>
<li>Merge 2 Map collections</li>
</ul>
<div>
<i>All code provided as-is. This is copied from my own code-base, May need some additional programming to work. Use for whatever you want, how you want! If you find this helpful, please leave a comment or share a link, not required but appreciated! :)</i><br />
<br />
Hope this helps someone out there!<br />
<br /></div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1265125331765205173.post-20247282710642352722018-03-11T18:32:00.000+01:002020-03-10T12:54:39.141+01:00Functional Adventures in F# - Calling F# from C#<div class="separator" style="clear: both; text-align: center;">
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-calling-f.html"><img border="0" data-original-height="421" data-original-width="750" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjy8tfqv7Ok_0f6Y3ydtQuW7JYW4hFM7NseiY_zkgyhrwhXzEbZIrCr71VHE7SFb_XiiXJtiPthIXDIXNI4BD_Wc7V2-gpSVuFIlwQSRfHXu08z1RdOAtWLc2DY3-lVblQJGSlFnspRJY/s1600/calling+fsharp+from+csharp.jpg" /></a></div>
<br />
I have quite a lot of code lying around that is written in C# and going into a new project, the most natural is to start with C# as the core application. Now when I am exploring the functional paradigm with F#, I still want to be able to call all the F# code from C#. In other words, the most natural is to add new functionality to my existing applications using F# and not try to accomplish the 'everything shall be written in F#' utopia.<br />
<br />
<b>This post is part of a series:</b><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-simple.html">Functional Adventures in F# - A simple planner</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-calling-f.html">Functional Adventures in F# - Calling F# from C#</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-using-map.html">Functional Adventures in F# - Using Map Collections</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-application.html">Functional Adventures in F# - Application State</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-types-with.html">Functional Adventures in F# - Types with member functions</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-getting-rid.html">Functional Adventures in F# - Getting rid of loops</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-getting-rid_22.html">Functional Adventures in F# - Getting rid of temp variables</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/04/functional-adventures-in-f.html">Functional Adventures in F# - The MailboxProcessor</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/05/functional-adventures-in-f-persisting.html">Functional Adventures in F# - Persisting Application State</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/05/functional-adventures-in-f-adding.html">Functional Adventures in F# - Adding Snapshot Persisting</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/06/functional-adventures-in-f-type-safe.html">Functional Adventures in F# - Type-safe identifiers</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/06/functional-adventures-in-f-event.html">Functional Adventures in F# - Event sourcing lessons learned</a><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<img border="0" data-original-height="239" data-original-width="750" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjumuuRD0LtItVcANYMLRXBPos3QBvjD-VeaW4PY9F5g03vsNa19234NNNgfhQa2vB5XdmwoaQBXCPZ_jPsA42fZ4qReIUHsHM6ouj8I3i6Hac4YWv3ApnKhwYqYWSMacPOUPbX7h6qqX8/s1600/fsharp+core+to+csharp+project+nuget.png" /></div>
So, first off. We need to give our C# project the knowledge of F# types. So lets Nuget the FSharp.Core package and we are all set!<br />
<br />
After that, calling the F# code from C# is easy. Lets use the code that we wrote in the last post with the Planner module.<br />
<br />
We had 2 different types described in the module, the ScheduledAction that was a record type and the Schedule that was a list of ScheduledActions.<br />
<br />
Lets look at some code:<br />
<pre>using System;
using Microsoft.FSharp.Collections;
namespace app.Components
{
public class Main
{
private FSharpList<Planner.ScheduledAction> _schedule;
public bool Shutdown { get; set; }
public void MainLoop()
{
while (!Shutdown)
{
var executableActions = Planner.getExecutableActions(DateTime.UtcNow, _schedule);
foreach (var action in executableActions)
{
Execute(action);
_schedule = Planner.removeFromSchedule(action, _schedule);
}
}
}
private void Execute(Planner.ScheduledAction action)
{
// execute business logic here
}
}
}
</pre>
<br />
As you an see, the Schedule type did not follow through as I expected. It is exposed a FSharpList<ScheduledAction>, i.e. we need to write the whole thing instead of just using Schedule. Other then that there seems to be nothing strange here. Planner is identified by intellisense as a class.<br />
<br />
If we try to modify the name of the ScheduledAction that we have received from the F# code, the code will not compile but instead show you the error<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><img border="0" data-original-height="70" data-original-width="613" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi17cdkEgWvnXEk3tjlgogLfNKYkID1PbfAyJTFUKU_zn7uioc3bTy6JXgZP0xqKIiiW6GRtd1LBOP2WNejly_VXy07OnuTkCKpVzhpBEaTGjcIbzXX6sP0EUn0cfmQf6qYqY8xODWk1G4/s1600/fsharp+stuff+is+immutable.png" style="margin-left: auto; margin-right: auto;" /></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><span style="font-size: small; text-align: start;">Property or indexer 'Planner.ScheduledAction.name' cannot be assigned to -- it is read only</span></td></tr>
</tbody></table>
This is due to that everything defined in F# is immutable (well almost everything).<br />
So that is that, it just reference the FSharp.Core and your F# project from your C# project and you are good to go.<br />
<br />
All code provided as-is. This is copied from my own code-base, May need some additional programming to work. Use for whatever you want, how you want! If you find this helpful, please leave a comment, not required but appreciated! :)<br />
<br />
Hope this helps someone out there!<br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1265125331765205173.post-57653255032466675502018-03-07T17:33:00.001+01:002020-03-10T12:54:33.126+01:00OpenGL 4 with OpenTK in C# Part 15: Object picking by mouse<div class="separator" style="clear: both; text-align: center;">
<a href="https://dreamstatecoding.blogspot.com/2018/03/opengl-4-with-opentk-in-c-part-15.html"><img border="0" data-original-height="532" data-original-width="752" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiR8gbz0CRAwic3yzg9JxuqNL6ArjAEaRuFoeZEEaEaF11isYgPu2KTh3O7X0n_SdPtzS0gJFkSbHeRz2qvmKZ-EsZWLT0EQ_bIRFg31gbKsk1ijmXuK7UHg7pRfdDmGaDIfBZSZsmytv8/s1600/opentk+header15+object+picking+by+mouse.png" /></a></div>
<br />
This time we will go through how to use the mouse to pick objects on the screen.<br />
<br />
This is part 15 of my series on OpenGL4 with OpenTK.<br />
<b>For other posts in this series:</b><br />
<a href="http://dreamstatecoding.blogspot.com/2017/01/opengl-4-with-opentk-in-c-part-1.html">OpenGL 4 with OpenTK in C# Part 1: Initialize the GameWindow</a><br />
<a href="http://dreamstatecoding.blogspot.com/2017/01/opengl-4-with-opentk-in-c-part-2.html">OpenGL 4 with OpenTK in C# Part 2: Compiling shaders and linking them</a><br />
<a href="http://dreamstatecoding.blogspot.com/2017/01/opengl-4-with-opentk-in-c-part-3.html">OpenGL 4 with OpenTK in C# Part 3: Passing data to shaders</a><br />
<a href="http://dreamstatecoding.blogspot.com/2017/01/opengl-4-with-opentk-in-c-part-4.html">OpenGL 4 with OpenTK in C# Part 4: Refactoring and adding error handling</a><br />
<a href="http://dreamstatecoding.blogspot.com/2017/02/opengl-4-with-opentk-in-c-part-5.html">OpenGL 4 with OpenTK in C# Part 5: Buffers and Triangle</a><br />
<a href="http://dreamstatecoding.blogspot.com/2017/02/opengl-4-with-opentk-in-c-part-6.html">OpenGL 4 with OpenTK in C# Part 6: Rotations and Movement of objects</a><br />
<a href="http://dreamstatecoding.blogspot.com/2017/02/opengl-4-with-opentk-in-c-part-7.html">OpenGL 4 with OpenTK in C# Part 7: Vectors and Matrices</a><br />
<a href="http://dreamstatecoding.blogspot.com/2017/02/opengl-4-with-opentk-in-c-part-8.html">OpenGL 4 with OpenTK in C# Part 8: Drawing multiple objects</a><br />
<a href="http://dreamstatecoding.blogspot.com/2017/02/opengl-4-with-opentk-in-c-part-9.html">OpenGL 4 with OpenTK in C# Part 9: Texturing</a><br />
<a href="http://dreamstatecoding.blogspot.com/2017/02/opengl-4-with-opentk-in-c-part-10.html">OpenGL 4 with OpenTK in C# Part 10: Asteroid Invaders</a><br />
<a href="http://dreamstatecoding.blogspot.com/2017/02/basic-bullet-movement-patterns-in.html" target="">Basic bullet movement patterns in Asteroid Invaders</a><br />
<a href="http://dreamstatecoding.blogspot.com/2017/02/opengl-4-with-opentk-in-c-part-11-mipmap.html">OpenGL 4 with OpenTK in C# Part 11: Mipmap</a><br />
<a href="http://dreamstatecoding.blogspot.com/2017/02/opengl-4-with-opentk-in-c-part-12-basic.html">OpenGL 4 with OpenTK in C# Part 12: Basic Moveable Camera</a><br />
<a href="http://dreamstatecoding.blogspot.com/2017/02/opengl-4-with-opentk-in-c-part-13.html">OpenGL 4 with OpenTK in C# Part 13: IcoSphere</a><br />
<a href="http://dreamstatecoding.blogspot.com/2017/02/opengl-4-with-opentk-in-c-part-14-basic.html">OpenGL 4 with OpenTK in C# Part 14: Basic Text</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/opengl-4-with-opentk-in-c-part-15.html">OpenGL 4 with OpenTK in C# Part 15: Object picking by mouse</a><br />
<br />
<h2>
Introduction</h2>
As I've written in previous posts, I'm still not that good with all the math etc. writing these posts is a way for me to learn and hopefully someone else out there finds it useful as well. This time I found a great post that goes into the details of ray-casting to pick objects in 3D space over at Anton Gerdelan's blog: <a href="http://antongerdelan.net/opengl/raycasting.html" target="_blank">antongerdelan.net/opengl/raycasting.html</a><br />
<br />
I've taken his base solution and made it work with the code-base that we use in this tutorial series. It did not work directly, so a lot of time was spent on what was going wrong.<br />
So, now that credit is where it belongs, lets look at the code.<br />
<h2>
Code</h2>
First we want to calculate the ray from our camera location based on the mouse click on the screen. So first we need to subscribe to mouse events. So in our OnLoad method, we will add the following event handler.<br />
<pre>MouseUp += OnMouseUp;
</pre>
<br />
In our event handler we will check that it is the correct button and send the coordinates to the actual object picking method
<br />
<pre>private void OnMouseUp(object sender, MouseButtonEventArgs mouseButtonEventArgs)
{
if (mouseButtonEventArgs.Button != MouseButton.Left)
return;
PickObjectOnScreen(mouseButtonEventArgs.X, mouseButtonEventArgs.Y);
}
</pre>
<br />
This is the method that calculates the ray from the camera and into the screen. It takes the mouse coordinates and then backtracks the transformations back to world space. For more details, check <a href="http://antongerdelan.net/opengl/raycasting.html" target="_blank">antongerdelan.net/opengl/raycasting.html</a>.<br />
<pre>private void PickObjectOnScreen(int mouseX, int mouseY)
{
// heavily influenced by: http://antongerdelan.net/opengl/raycasting.html
// viewport coordinate system
// normalized device coordinates
var x = (2f * mouseX) / Width - 1f;
var y = 1f - (2f * mouseY) / Height;
var z = 1f;
var rayNormalizedDeviceCoordinates = new Vector3(x, y, z);
// 4D homogeneous clip coordinates
var rayClip = new Vector4(rayNormalizedDeviceCoordinates.X, rayNormalizedDeviceCoordinates.Y, -1f, 1f);
// 4D eye (camera) coordinates
var rayEye = _projectionMatrix.Inverted() * rayClip;
rayEye = new Vector4(rayEye.X, rayEye.Y, -1f, 0f);
// 4D world coordinates
var rayWorldCoordinates = (_camera.LookAtMatrix.Inverted() * rayEye).Xyz;
rayWorldCoordinates.Normalize();
FindClosestAsteroidHitByRay(rayWorldCoordinates);
}
</pre>
<br />
After that we need to add a method that checks if the game object has been hit by the ray. I added this to the AGameObject class so that all game objects can be picked. Basically we begin by checking if the origin of the ray is inside the sphere that we are checking against. After that we check if the ray is pointing away from the object and lastly we perform Pythagorean method to determine if the ray is within the radius of the sphere that we are looking at. This ray method is something that I've had lying around for a while and used for various purposes.<br />
<br />
<pre>public double? IntersectsRay(Vector3 rayDirection, Vector3 rayOrigin)
{
var radius = _scale.X;
var difference = Position.Xyz - rayDirection;
var differenceLengthSquared = difference.LengthSquared;
var sphereRadiusSquared = radius * radius;
if (differenceLengthSquared < sphereRadiusSquared)
{
return 0d;
}
var distanceAlongRay = Vector3.Dot(rayDirection, difference);
if (distanceAlongRay < 0)
{
return null;
}
var dist = sphereRadiusSquared + distanceAlongRay * distanceAlongRay - differenceLengthSquared;
var result = (dist < 0) ? null : distanceAlongRay - (double?)Math.Sqrt(dist);
return result;
}
</pre>
<br />
The above method is called from the following that iterates all the objects currently active in the game and then tries to find the object that is closest (if there are many) to the origin of the ray.<br />
<br />
<pre>private void FindClosestAsteroidHitByRay(Vector3 rayWorldCoordinates)
{
AGameObject bestCandidate = null;
double? bestDistance = null;
foreach (var gameObject in _gameObjects)
{
if (!(gameObject is SelectableSphere) && !(gameObject is Asteroid))
continue;
var candidateDistance = gameObject.IntersectsRay(rayWorldCoordinates, _camera.Position);
if (!candidateDistance.HasValue)
continue;
if (!bestDistance.HasValue)
{
bestDistance = candidateDistance;
bestCandidate = gameObject;
continue;
}
if (candidateDistance < bestDistance)
{
bestDistance = candidateDistance;
bestCandidate = gameObject;
}
}
if (bestCandidate != null)
{
switch (bestCandidate)
{
case Asteroid asteroid:
_clicks += asteroid.Score;
break;
case SelectableSphere sphere:
sphere.ToggleModel();
break;
}
}
}</pre>
<br />
As you can see above, we have introduced a new GameObject for this part of the tutorial series, the SelectableSphere. It looks like the following:<br />
<pre>public class SelectableSphere : AGameObject
{
private ARenderable _original;
private ARenderable _secondaryModel;
public SelectableSphere(ARenderable model, ARenderable secondaryModel, Vector4 position, Vector4 direction, Vector4 rotation)
: base(model, position, direction, rotation, 0)
{
_original = model;
_secondaryModel = secondaryModel;
}
public override void Update(double time, double delta)
{
_rotation.Y = (float) ((time + GameObjectNumber) * 0.5);
var d = new Vector4(_rotation.X, _rotation.Y, 0, 0);
d.Normalize();
_direction = d;
base.Update(time, delta);
}
public void ToggleModel()
{
if (_model == _original)
_model = _secondaryModel;
else
_model = _original;
}
}
</pre>
Basically an endlessly rotating sphere that will toggle its model when selected.<br />
<br />
And lastly we generate these spheres in 2 layers in the OnLoad method in our MainWindow to have stuff on screen that can be selected.<br />
<pre>var maxX = 2.5f;
var maxY = 1.5f;
for (float x = -maxX; x < maxX; x += 0.5f)
{
for (float y = -maxY; y < maxY; y += 0.5f)
{
_gameObjects.Add(_gameObjectFactory.CreateSelectableSphere(new Vector4(x, y, -5f, 0)));
}
}
for (float x = -maxX; x < maxX; x += 0.65f)
{
for (float y = -maxY; y < maxY; y += 0.65f)
{
_gameObjects.Add(_gameObjectFactory.CreateSelectableSphereSecondary(new Vector4(x, y, -6f, 0)));
}
}
</pre>
<br />
<br />
<h2>
End results</h2>
<div style="text-align: center;">
<iframe allowfullscreen="" frameborder="0" gesture="media" height="315" src="https://www.youtube.com/embed/bKjQUfWZ8fM" width="560"></iframe>
</div>
<br />
<span style="font-family: "times new roman";">For the complete source code for the tutorial at the end of this part, go to: </span><a href="https://github.com/eowind/dreamstatecoding" style="font-family: "times new roman";">https://github.com/eowind/dreamstatecoding</a><br />
<div>
<br /></div>
So there, thank you for reading. Hope this helps someone out there : )<br />
<br />
<br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1265125331765205173.post-90790712881781472292018-03-04T12:42:00.003+01:002020-03-10T12:54:28.398+01:00Functional Adventures in F# - A simple planner<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-simple.html"><img border="0" data-original-height="421" data-original-width="750" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiBmIyyh6zbvo0gTCHSBsBYmstgs3IUlzYde8q99BmHv2Yt_gaUqu1nRSyl5F0n1YlcGZyHrH6U7RnFL_O87GU5IDCpY3RRY6bt38PjrWOoeGs2QV7jcb0qq2q7_CHmejT2IhCU91EIpw/s1600/a+simple+planner.jpg" /></a></div>
<br />
Last year when I got sick I bought the openGL Bible and <a href="http://dreamstatecoding.blogspot.com/p/opengl4-with-opentk-tutorials.html">started writing about graphics programming with openTK in C#</a> just to keep my mind occupied.<br />
This year <a href="http://dreamstateliving.blogspot.com/2018/01/another-reminder-of-mortality.html" target="_blank">things turned bad again</a>, so a new book... This time it is time for F# as I got really curious about functional programming during the last few months.<br />
<br />
<b>This post is part of a series:</b><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-simple.html">Functional Adventures in F# - A simple planner</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-calling-f.html">Functional Adventures in F# - Calling F# from C#</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-using-map.html">Functional Adventures in F# - Using Map Collections</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-application.html">Functional Adventures in F# - Application State</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-types-with.html">Functional Adventures in F# - Types with member functions</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-getting-rid.html">Functional Adventures in F# - Getting rid of loops</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/03/functional-adventures-in-f-getting-rid_22.html">Functional Adventures in F# - Getting rid of temp variables</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/04/functional-adventures-in-f.html">Functional Adventures in F# - The MailboxProcessor</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/05/functional-adventures-in-f-persisting.html">Functional Adventures in F# - Persisting Application State</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/05/functional-adventures-in-f-adding.html">Functional Adventures in F# - Adding Snapshot Persisting</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/06/functional-adventures-in-f-type-safe.html">Functional Adventures in F# - Type-safe identifiers</a><br />
<a href="https://dreamstatecoding.blogspot.com/2018/06/functional-adventures-in-f-event.html">Functional Adventures in F# - Event sourcing lessons learned</a><br />
<br />
So previous experience with functional ideas are from web tech like Redux and writing the core engine of my latest game project in C# with functional constructs. If you want to know more about that project you can read here:<br />
<a href="http://dreamstatecoding.blogspot.com/2017/09/functional-adventures-in-net-c-part-1.html" target="_blank">Functional adventures in .NET C# - Part 1, Immutable Objects</a><br />
<a href="https://dreamstatecoding.blogspot.com/2017/10/functional-adventures-in-net-c-part-2.html">Functional adventures in .NET C# - Part 2, Application State</a><br />
<br />
So, next step is to actually use a language that is built for this. And luckily in .NET there is a full featured one.<br />
<br />
At first I thought about converting a already existing piece of C# to F# to see the similarities and differences but I quickly omitted that idea. So for the next few posts I will try to write a Scheduler with F#.<br />
<i><br /></i>
<i>If you do not have any development environment, please check out <a href="https://www.visualstudio.com/vs/community/" target="_blank">Visual Studio Community Edition</a>, it is a great and free environment that I use for my private projects. It has support for F#.</i><br />
<h2>
Defining data</h2>
As a first step we need to define the different types of data that we have.<br />
<br />
Step 1, decide if we should use CLI types or F# specific types.<br />
<br />
<b>CLI Types</b>: Standard types that can be used in all .NET languages<br />
<b>F# Types</b>: Specific to F#, cannot be used outside. Designed with functional paradigm in mind and does not have null and are immutable. They also have built in equality checking and pretty printing.<br />
<br />
Our choice here will be F# types to be able to use the language to its full extent as it was designed.<br />
As a starter, we want to be able to build a collection of planned Actions. So lets first define what we will be planning.<br />
<pre>type ScheduledAction = { time:DateTime; name:string; }
</pre>
This pretty much describes a new Record type that has a time and a name.<br />
Next lets define the Schedule as an ImmutableSortedSet<br />
<pre>type Schedule = ScheduledAction list
</pre>
Nothing fancy here either, as you can see compared to C# the order of things is switched, where we would write list<ScheduledAction> we just write ScheduledAction litinstead. I think you can use the C# notation as well but I am trying to stick with the way my book says is the F# way.<br />
<br />
<h2>
Adding functionality</h2>
Next we will want to add a ScheduledAction to the current Schedule. As everything is immutable we will define a function that takes the new ScheduledAction and the current Schedule, and returns a new Schedule with the ScheduledAction added to it. We will not change the current Schedule, just return a new Schedule with the change made to it.<br />
So just add a new item.<br />
<pre>let schedule (action:ScheduledAction) (currentPlan:Schedule) =
let newPlan = action :: currentPlan
newPlan
</pre>
Here we define the function schedule that takes 2 arguments: action and currentPlan. The parenthesis are not needed if you do not supply the type arguments. But my compiler complained (FS0613<span style="white-space: pre;"> </span>Syntax error in labelled type argument) if I didn't add them so hence the parenthesis.<br />
The item :: tail construct takes an item and a list and returns a new list with the item as the first item and the tail as ... the tail.<br />
<br />
Next step is to retrieve actions that should be executed. So lets define a new function, this will not change the plan, just return a new list with items that should be executed.<br />
<pre>let getExecutableActions (currentTime:DateTime) (currentPlan:Schedule) =
let actions = List.filter (fun x -> x.time <= currentTime) currentPlan
actions
</pre>
Here we use the List.filter function to apply a filter to each item in the list. As Schedule is a list this works fine.<br />
<br />
Finally we want to remove items that have been executed (in some way, outside of scope here).<br />
<pre>let removeFromSchedule (action:ScheduledAction) (currentPlan:Schedule) =
let newPlan = List.filter (fun x -> compare x action <> 0) currentPlan
newPlan
</pre>
Basically the method is the same as the above, but it compares each element in the list to the one we want to remove, and if it is the one we want to remove, we just do not add it to the new list. I.e. filter it away.<br />
<br />
<h2>
The complete planner module</h2>
<pre>namespace scheduler
module Planner =
open System
type ScheduledAction = { time:DateTime; name:string;}
type Schedule = ScheduledAction list
let schedule (action:ScheduledAction) (currentPlan:Schedule) =
let newPlan = action :: currentPlan
newPlan
let getExecutableActions (currentTime:DateTime) (currentPlan:Schedule) =
let actions = List.filter (fun x -> x.time <= currentTime) currentPlan
actions
let removeFromSchedule (action:ScheduledAction) (currentPlan:Schedule) =
let newPlan = List.filter (fun x -> compare x action <> 0) currentPlan
newPlan
</pre>
So here we have the complete planner in 18 lines of code.<br />
<h2>
Adding unit tests</h2>
Of course we should have unit tests to ensure correct functionality. Luckily F# makes it quite easy to write tests as well.<br />
<pre>namespace scheduler.tests
open System
open Microsoft.VisualStudio.TestTools.UnitTesting
open scheduler
open scheduler.Planner
[<TestClass>]
type PlannerTests () =
[<TestMethod>]
member this.Planner_schedule_AddItemToEmptySchedule () =
let item : ScheduledAction = { time = DateTime.UtcNow; name = "first item" }
let target : Schedule = []
let newSchedule = schedule item target
Assert.AreEqual(item, newSchedule.Head);
[<TestMethod>]
member this.Planner_schedule_AddItemToNonEmptySchedule () =
let item : ScheduledAction = { time = DateTime.UtcNow; name = "first item" }
let item2 : ScheduledAction = { time = DateTime.UtcNow; name = "second item" }
let target : Schedule = []
let intermediateSchedule = schedule item target
let newSchedule = schedule item2 intermediateSchedule
Assert.AreEqual(item2, newSchedule.Head);
Assert.AreEqual(2, newSchedule.Length);
</pre>
For the schedule function, we add 2 tests, one that adds a new item to an empty Schedule, and one that adds an extra item to a Schedule that already has items.<br />
<pre>
[<TestMethod>]
member this.Planner_getExecutableActions_EmptySchedule () =
let target : Schedule = []
let actual = getExecutableActions DateTime.UtcNow target
Assert.AreEqual(0, actual.Length);
[<TestMethod>]
member this.Planner_getExecutableActions_SingleItemSchedule_NoExecutable () =
let currentTime = DateTime.UtcNow;
let item : ScheduledAction = { time = currentTime; name = "first item" }
let target : Schedule = []
let newSchedule = schedule item target
let currentTime = currentTime.AddSeconds(-2.0);
let actual = getExecutableActions currentTime newSchedule
Assert.AreEqual(0, actual.Length);
[<TestMethod>]
member this.Planner_getExecutableActions_SingleItemSchedule_SingleExecutable () =
let currentTime = DateTime.UtcNow;
let item : ScheduledAction = { time = currentTime; name = "first item" }
let target : Schedule = []
let newSchedule = schedule item target
let currentTime = currentTime.AddSeconds(2.0);
let actual = getExecutableActions currentTime newSchedule
Assert.AreEqual(1, actual.Length);
[<TestMethod>]
member this.Planner_getExecutableActions_MultiItemSchedule_SingleExecutable () =
let currentTime = DateTime.UtcNow;
let item : ScheduledAction = { time = currentTime.AddYears(1); name = "first item" }
let item2 : ScheduledAction = { time = currentTime; name = "second item" }
let target : Schedule = []
let intermediateSchedule = schedule item target
let newSchedule = schedule item2 intermediateSchedule
let currentTime = currentTime.AddSeconds(2.0);
let actual = getExecutableActions currentTime newSchedule
Assert.AreEqual(item2, actual.Head);
Assert.AreEqual(1, actual.Length);
</pre>
For the getExecutableActions function we add 4 tests.<br />
<br />
<ul>
<li>One that checks so that the special case of an empty Schedule is handled correctly. </li>
<li>Secondly that the time filter is correct when we have a single item in the list that is not OK to execute yet. </li>
<li>Thirdly a single item that is OK to execute</li>
<li>and lastly a Schedule with multiple items with 1 able to execute and 1 not able to</li>
</ul>
<br />
<pre> [<TestMethod>]
member this.Planner_removeFromSchedule_RemoveItem () =
let item : ScheduledAction = { time = DateTime.UtcNow; name = "first item" }
let item2 : ScheduledAction = { time = DateTime.UtcNow; name = "second item" }
let target : Schedule = []
let intermediateSchedule = schedule item target
let newSchedule = schedule item2 intermediateSchedule
let actual = removeFromSchedule item newSchedule
Assert.AreEqual(item2, actual.Head);
Assert.AreEqual(1, actual.Length);
</pre>
And lastly we check that removeFromSchedule function does just that, removes the item we want to remove and leaves the rest in the list. (in the new list that is returned, the original is not changed... remember immutable)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMdoK-bOEGeaFS4gaIfsPacsx_wDEupSOSnU8aTgAnOowNxCIoWjztWliMR9bgyy7I1Foos9aeORpfjLMlnUnOjMSWjZU3Lt9LongGe6XH99wG5liFG4pjqaryN22prJxrNIAI8VqPwok/s1600/unit+tests.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="242" data-original-width="486" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMdoK-bOEGeaFS4gaIfsPacsx_wDEupSOSnU8aTgAnOowNxCIoWjztWliMR9bgyy7I1Foos9aeORpfjLMlnUnOjMSWjZU3Lt9LongGe6XH99wG5liFG4pjqaryN22prJxrNIAI8VqPwok/s1600/unit+tests.png" /></a></div>
<br />
All code provided as-is. This is copied from my own code-base, May need some additional programming to work. Use for whatever you want, how you want! If you find this helpful, please leave a comment, not required but appreciated! :)<br />
<br />
Hope this helps someone out there!<br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1265125331765205173.post-79268704858645745002018-01-17T22:02:00.004+01:002020-03-10T12:54:22.903+01:00Wings3D basic spacecraft modelling<br />
<div style="text-align: center;">
<iframe allowfullscreen="" frameborder="0" gesture="media" height="315" src="https://www.youtube.com/embed/9ps7lxME5Lg" width="560"></iframe>
</div>
<br />
After trying to use Blender each time I've wanted to model anything in 3D and pretty much closing the application after 5 minutes as it just makes me stressed I was quite happy when I heard about <a href="http://www.wings3d.com/" target="_blank">Wings3D</a>. A free, no bullshit, simple to use, 3D modeller that lets you model 3D models.<br />
<br />
I decided to try it out with modelling a simple (can't really stress how simple here...) spacecraft with it.<br />
<br />
I played around with the tool for maybe 10 minutes before starting to record, i.e. I figured out how to do this and then recorded it.<br />
<br />
All commands are on the context menu that is accessed by right-clicking anywhere.<br />
There are 4 modes of selection: Vertex, Edge, Plane or Object.<br />
In this example I will sculpt half of a spaceship from a cube and then duplicate and flip it so that it becomes a whole ship.<br />
<br />
Hope this helps someone out there!<br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1265125331765205173.post-77422739435948642982017-12-21T21:39:00.000+01:002020-03-10T12:54:18.199+01:00WinForms TextBox Get as Double or Integer<div class="separator" style="clear: both; text-align: center;">
<img border="0" data-original-height="280" data-original-width="750" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioPLJzsKlEHcKxpH0Hsr7guVd14ZvK2kq9_dPTxowMO_f_TetBslhx9DC2WajBeyWSVI-lxQ_nzomlFUTbaz8dGnhRZUyehTt79RLYnBMz7l8hGK0g1QmJK0m1CoO8b8YWSjlu0qZ3mn8/s1600/WinForms+TextBox+Get+as+Double+or+Integer.jpg" /></div>
I always end up returning to Windows Forms when I want to code some tool or prototype an idea. This time I just want to share two extension methods for retrieving the contents of a TextBox as an Integer or a Double.<br />
<br />
<pre>public static double AsDouble(this TextBox textBox)
{
var s = textBox.Text.Replace(",", ".").Trim();
return double.TryParse(s, out var d) ? d : double.NaN;
}
public static int AsInt(this TextBox textBox)
{
var s = textBox.Text.Trim();
return int.TryParse(s, out var i) ? i : 0;
}
</pre>
<br />
The colon to period replacement is to ensure that Swedish formatting works with the default parser. No guarantee that it will work with all cultures.<br />
<br />
<br />
All code provided as-is. This is copied from my own code-base, May need some additional programming to work. Use for whatever you want, how you want! If you find this helpful, please leave a comment, not required but appreciated! :)<br />
<br />
Hope this helps someone out there!<br />
<br />Unknownnoreply@blogger.com0