>> In this episode of the ON.NET Show,
we're going to have Phillip Carter
coming back again to talk about
what are some of the new things
that are inside of F# 4.5?
Welcome to another episode of the ON.NET Show.
My name is Celso Philip and I have joining me again,
Phillip Carter. What's going on man?
>> Nothing much. Just having a good time.
>> This is like your third time on the show now, right?
>> Yeah. Well, back in the early days of the show,
I was on there for a few times.
I had like two hour-long F# ones.
>> Oh wow.
>> Yeah. Those were a little out of control.
>> Wow, that's a lot of F#.
>> Yeah.
>> So what are you here to talk to us about today?
>> So I'm here to talk today about F# 4.5.
>> 4.5?
>> Yes.
>> I think the last time that you're on,
we're at F# 4.1.
>> Yes, 4.1, so we jumped up a few digits.
>> Okay.
>> Well, decimal places I guess.
>> Decimal points.
>> Yeah. So, it's actually kind of interesting
because the last version was F# 4.1,
but now it's F# 4.5, and so you might be thinking,
well, what happened in those four places?
>> Sure.
>> Well, versioning is something that's always fun,
and everybody always gets it right every single time.
>> Of course.
>> Yeah.
So there was some really interesting historical stuff
that occurred in the past with F#,
where basically F#, the compiler,
depends on the FSharp.Core binary,
which is its core library.
It's got definitions for what an Int is, what void is,
things like that, and there's been some new additions
and things like that as time has progressed.
But up until, it was all like just one thing
until you got to .NET Framework 4.0
and so then, there was a split between
.NET Framework 4.0 world and previous world
and because it was a different runtime,
there was then a different version
attached to that binary,
and so you would get version
LanguageMajorVersion.LanguageMinorVersion.Something,
and then there would be an older one.
Then time progressed, and then NuGet got more and
more like a central part of developers lives with .NET
and there was NuGet package for FSharp.Core,
and that version number was
not the same as the actual binary,
and that got even worse as that NuGet package
then rubbed somewhat semantically,
so that there were to be
different minor versions as new things were coming in,
but it would carry a completely different binary.
So you had this weird world where at one point I believe
we had F# language version 4.1,
FSharp.Core binary version 4.4.1.0
and FSharp.Core package version 4.3.4.
So that made no sense to anybody.
>> Right. So the version was a little crazy there.
>> Yeah, and that was just something where
just standard engineering processes of
versioning stuff just sort of led down that path
and we were like, "Whoa. Okay."
So, the only way to reasonably progress forward
and have a version number for everything
that was at least sort of aligned
about major language version,
minor language version, was 4.5.
>> Okay.
>> So now we have F# language version 4.5,
FSharp.Core NuGet package version 4.5.Patch,
and then we have FSharp.Core binary version inside of
that NuGet 4.5. whatever.
>> Sure.
>> So they're not exactly the same numbers
but at least they have the
first two digits that are the same
and we intend on keeping it that way from now on.
>> Sure. It's a little bit more consistent now,
so it's easier for people to see
like what pieces go together.
>> Yeah, and that's one of those things that starting out
as an F# programmer you never really ran into as much,
but then once you started caring about like, "Okay.
Well, what binaries do I actually have?
Boom. Big confusion.
So hopefully, this makes things a lot nicer.
>> Nice. So why don't we talk a little bit about
where exactly we can get started
and where can we actually get these bits from?
>> Yeah. Absolutely.
So we got a handy-dandy website right here.
The .NET homepage and there's an F# page right here
that's just, you can actually visit it if you go
aka .ms/fsharphome. It'll take you there.
So we've got a nice little tagline
and most importantly, a big old button that says,
"Get Started with F#."
This will have you download the .NET
SDK which has .NET Core and all that stuff in there.
This will give you the latest ones.
This will give you F# 4.5 inside of it.
So basically, if you install .NET Core,
you already have F# actually,
but if you don't have .NET Core for some reason,
this is definitely the easiest way to get started
because this will work obviously across platform,
it works inside of Visual Studio, it works in VS for Mac,
VS code, basically anywhere you want.
>> So not only too do I get
the F# compiler and the F# tools,
but I also get the templates as well, right?
>> Yeah. So you get some basic templates
out of the box with the .NET CLI.
So like in this case,
the little tutorial says dotnet new console-lang.
That's like a little console app
but there's like ASP.NET Core library,
sorry, ASP.NET Core templates like library templates,
and then if you want to use other stuff,
there's a fantastic library called Giraph which
is for building web services on .NET Core.
It uses ASP.NET Core stuff onto the background.
Well, they have their own templates,
and so you can actually use
the .NET CLI to just do .NET new,
well, there's like a way
to install templates from a NuGet package,
and so you can just have that.
So there's also a lot of
community stuff out there that you can
get by using different libraries.
>> Right. So I remember, in the previous episode,
you did come on and talk to us about Giraph a little bit.
>> Yeah.
>> You can make sure that we add in that short note,
so everybody can take a look at that episode
and see all the good stuff you do with Giraph.
>> Yeah. Absolutely, and I think
Giraph recently released version 3.0 since that video.
So it's pretty stable.
>> Nice.
>> I recommend trying it out for sure.
>> Nice. That's good.
>> Yeah. So that's basically just how you get started.
Now, you can also use Visual Studio,
and so I'm just going to move on over there.
So if you use Visual Studio
and you get the latest stable version,
so that's 15.8, I think it's .6.
It's sort of the updates version right now, that'll hatch.
If you download it that'll be the one you'll get.
This comes with the exact same binaries,
like the exact same core library,
compiler, as you would get in the .NET Core SD.
Actually this will install that
same .NET Core SDK that you download from site.
So if you're on Windows Visual Studio, you got everything.
>> Good. Sounds pretty good. So why don't we
talk about some of the new features, right?
Like what exactly are we getting now in F# 4.5?
>> Yeah. Absolutely. So first of all,
you get some new version numbers.
It's not a language feature so to speak.
So for those of you who've been
following C#'s progression and .NET
Core's progression with some of
the new stuff involving Span,
which is sort of this low-level,
basically it's a pointer and offset somewhere in memory.
There's all sorts of safety features and efficiencies
built into the runtime for this construct,
and it's been surfaced as language
features in newer C# versions.
Well, we did the exact same thing over in F#.
So I think the granularity that I chose
was about nine features around Spans by itself.
>> Really?
>> I'm not going to talk about every single one of them.
So we introduced the concept of a void pointer in F#,
but that's just sort of something that you'll
just kind of use if you're doing
more advanced programming but-.
>> Sure. So, really quickly.
Why don't you tell us what exactly is a Span,
and what are some of
the use cases would use that type of-?
>> Yeah. Absolutely. So basically, the scenario is,
you want to do high-performance stuff
without having to drop down
into native code like with C++ and so, I mean,
there are a lot of scenarios where
you've got to do that anyway.
So it's not something that you should
necessarily avoid at all costs,
but there are a lot of people who are saying, "Yeah,
but I just want to not allocate a ton and a ton of
strings by doing like really
basic programming," and so we sort of said, "Okay.
Is there a way that you can do
this sort of stuff and manage code and sort of
have the safety benefits that you get in .NET,
but you still get a bit more that native performance? "
So the way that you accomplish that is you
restrict things that you can
actually do with these constructs.
>> Got you.
>> So if you look at this code sample right here,
you'll notice there's two things here.
There's this inref and outref construct.
An inref right there,
and, sorry, not outref.
I meant byref.
So all a byref is, it says,
represents a managed pointer in
F Sharp code, and that's all it is.
So this is just a pointer that exists somewhere.
So if you've been doing C programming
or C++ programming, you know the pointers.
You can do all sorts of wacky stuff with them.
That buys you efficiencies,
but it's also very unsafe.
So this basically says, well,
you can do a lot less of the wacky stuff,
but you get a lot of the safety.
So if we walk through some of this code here,
I just have a really basic function called print that
just takes an inref event, and then, it prints it out.
But, say, I want to do something unsafe.
Well, not necessarily unsafe,
but something that you wouldn't expect.
So inref is basically a read-only managed pointer.
Say, I want to go, well,
I'm going to mutate that to be the value 12.
Well, that doesn't work.
So I get squiggles there saying that this is read only,
so the write is not permitted.
This is the thing because
F Sharp uses type inference very heavily for things.
When you start using these constructs,
we will infer to the inref as much as we can.
They basically serve because we are
immutable by default with all of our binding.
So it would also makes sense for our pointers to
be read only by default,
if you're relying on inference.
So, in this case, I specified the type explicitly,
but this is an inref is what
you're going to see a lot in F Sharp code.
So you run into that.
Now, if you are actually
doing something where you're like, yes,
I want to mutate the value,
then,you use a byref.
A byref is just like, it's read-write.
So in this case, I could print out the value,
I could set it equal to itself times itself,
and then, print it out again, and do something like that.
So the way that you use
inrefs and byrefs varies very slightly.
So in this case, I've defined a value called num,
which is initially a value 12.
This is an immutable value.
I can't change this without the code compiling.
But I can still actually pass a reference to that,
like a pointer to that value to the print function,
because print, it's just a read only thing.
So I'm not actually going to be mutating it.
So the way that you actually do that is,
you just use the ampersand keyword,
and that just says, take a reference of this,
which is, in this case, a pointer.
It's the exact same way that you would
pass by reference in F Sharp,
which coincidentally also uses
the byref and inref constructs.
We're saying, not only is it for pass by reference,
but it's for all this stuff.
>> Got it.
>> For the second function,
I can't just do this.
Say, I delete this.
This is not going to work. Type mismatch.
Expecting a byref, but I gave it an inref.
I'm basically saying, treat num as
an inref because this
is effectively using type inference and saying,
well, treat this as what it is.
It is an immutable value,
so we turn it into an inref.
So, what you need to do is,
you need to actually establish
something to be mutable upfront,
if you want to pass something in as a byref,
because that's sort of, okay,
this value can change.
So then, I'm going to use
the construct that allows you to change things.
That's the way that works.
Then, there's also one thing that I want to call out here,
an actual intentional compiler error.
So we also have scoping rules for byrefs.
This is something that's entirely new and after our 4.5.
So say, I wanted to find this value X that's a byref.
Then, inside, I wanted to find a value Y that's mutable.
Then, it doesn't necessarily have to immutable,
but then, basically say,
return the reference of this internally defined value.
Well, that's actually an unsound
thing because being able to say,
give me a pointer to a thing that I defined in
a scope that is now effectively finished.
So like this right here,
say, you were to do something even more dangerous,
like let's mutable Y
equals 12 and try to have it escape its scope like this.
Well, it's for the same rules.
This is not going to work because
it was defined within the scope of this function.
So I can't just have this pointer
pointing to this thing
that is effectively being reinitialized all the time.
That's something that'll just lead to crazy bugs.
You're very likely to end up
crashing your application if you depend on that.
It's for some reason. So, that's why we
just make it a compiler error straight off the bat.
So, we restrict your usage of this stuff.
But with that restriction,
you get certain efficiencies,
and you can know that you're
not going to completely blow up if you do that.
>> Right. So I think the compiler now is able to
optimize some of these operations
now because it knows exactly,
am I mutating this thing or not.
Then, like you say, you get some of that safety,
some of those safeguards around.
Let me not shoot myself in the foot by
doing some crazy [inaudible] arithmetic.
>> But speaking of things that you can do,
that might still be a bit unexpected.
So I got this fun little function
called Sequenceinator5000.
>> Sequenceinator5000.
>> Yeah, it's a good one.
>> Okay. What does this do?
>> This has got just an array of
numbers, just some values in it.
Then, I just have a two string
override inside of this class,
that just basically just string
dot joins a space in between each of the values.
Then, I have a method
in here called FindLargestSmallerthantarget.
So basically, given an int,
find the largest value that's still
smaller than that integer,
except there's a key difference.
You'll notice, instead of
passing a value that corresponds to,
hey, I found the index,
I'm going to pass the value that's back to that,
I'm passing a reference to that value,
which is actually a pointer to
that space in the underlying number array.
So what's interesting there is, if I use it, say,
I set my target to be 16,
I'm actually going to be doing
a byref return for this method.
So rather than just returning the value,
I'm returning the pointer.
I can treat that as a reference that I can then mutate.
So let me just run this,
just show you why this is interesting.
>> Sure.
>> I'll start without debugging here.
I think I set the correct one.
It's startup. All right.
Cool. So the first one is 1,
3, 7, 15, [inaudible].
But then you notice it's 1, 3, 7, 30.
This is a bit different.
The reason why is because
I use that same ampersand right there,
and then, I invoke the method and I get the results.
Then, I change it to be itself multiplied by two.
In this case, I'm not grabbing
a value and then just changing that value just inside.
>> In this space.
>> Where I'm at right now. I'm actually saying,
no, mutate the thing that's in there.
This is a pattern that's used for Unity
and other game programming, and things like that.
That's at least one of the major use cases.
So this is something
that's C Sharp has supported for a bit,
and we supported consuming them in F Sharp 4.1.
But we did not support production of
these byref returns up until now.
So now, we support both consumption and production.
So you can interrupt perfectly.
So you can send the thing that
a C Sharp component may be expecting.
You can do that same manipulating
pointer stuff with
Unity programming, which is pretty cool.
>> Right. That's awesome.
>> Yeah. So, speaking of perf,
so I'll show you a benchmark of this,
but let me give you a short scenario.
So imagine you've got a web server,
you're processing a bunch of strings in there,
and you need to do something really basic,
like, I've got some sort of separator.
In this case it's a comma, but
it's it doesn't have to be a comma.
>> I'm just doing some type of parsing, right?
>> Yeah.
>> I'm trying to pull information out of that-
>> Yeah. So, this is like just a trivial function,
but you do this stuff all the time actually
if you're in some high-performance thing,
where you're like, no I know
that data's going to exist at this point.
I want to extract a little pieces of
it and then do something with that.
And that portion of extract a little pieces of data
out may very well be
a hot loop in something that you're doing that,
it could actually be a bottleneck.
So pretty much idiomatic F sharp code
in this case is just, okay,
I got a string, find the position of the thing,
in this case, it's a comma,
parse out a value that's, in our case,
from zero up until that position like what's
the value that's just next to it right there,
and then what's the next value,
and then return a tuple that's comprised of those both.
That's fairly straightforward,
most people should be pretty happy,
but if you need to do that in a hot loop
where you got just thousands and thousands,
perhaps millions of strings,
you can start to allocate a whole lot.
So you may want to rewrite that.
So this is where Span of T,
and some of the Struct,
and just by reflect,
stuff comes into play.
So the way that you write it
is actually almost identical.
So in this case, I'm just going to have a Span,
and I'm just going to take str,
then I'm going to go AsSpan in this case.
So, that's a number that's sitting on string.
So, then I'm basically just going to write
this exact same code right here,
but then instead of string, str.indexOf,
I'll just do span.indexOf, and so on.
Let me just copy and paste that,
save you my terrible typing there.
In this case, this will be the slice method rather
than the substring method. There we go.
>> You're going to change a lot of expensive.
>> Oh yeah. There we go.
Yeah. See? Compiler helping me out,
but I didn't even bother to look at it.
Then one last change, rather than a regular tuple,
because regular tuples and F-sharp are reference types,
I'm just going to turn this into a sharp tuple.
So, this is something that actually existed
in F sharp 4.1.
Prior to F sharp 4.5,
you actually could write code like this,
but the compiler didn't
really have a deep understanding of what was going on,
and so we weren't necessarily
emitting all the correct stuff.
So, if you were to run this now,
like I have some code for Benchmark.net,
I'm not going to sit you through that,
because it runs a whole bunch of different iterations,
but there's quite a difference.
So, when I ran that actually on my Mac,
I didn't even use the parallels
and since that I'm sitting in,
you'll notice this little table here,
the old version, took
almost about four seconds to run on average,
and the new one takes about
1.5 seconds to run on average.
>> Oh wow. That's kind of cool.
>> That's kind of cool. So that's faster.
But the thing that I really
like is if you look at total allocated,
in this case, I had I think 10 million strings.
I said, okay, parse out 10 million strings.
In this case, it allocated
almost a gigabyte to
parse that stuff with the old version,
and the new one allocated 76 Megs.
>> That's crazy.
>> Yeah.
> I find a lot of the parse work that's been going on,
particularly in the .NET community,
has been around, how can we efficiently manage strings?
>> Yes.
>> That seems to be like a huge
bottleneck for a lot of folks,
and particularly we're doing stuff like the parsing,
like with Json and XML,
and a lot of these return types,
especially for web servers,
we return a lot of these types of data types and we
don't really think about the path that comes in along.
We just say, "Oh, here's a list of stuff,
serialize this understanding over
the wire." You know what I mean?
>> Yeah, and that sort of stuff,
just getting your job done,
just have some strings,
move them through, copy stuff
around, allocate new strings.
That's totally fine, but
then all of a sudden you're like, "Oh, crap.
This thing now needs to have a really high load
coming into it," and then all of
a sudden all those allocations,
they really start to really hit you
over long spans of time, because, I mean,
honestly the difference for
a single run between four seconds
versus 1.5 seconds is not like that big of a deal,
but that memory allocation is
huge because if this thing is running for
like hours at a time
or basically just running perpetually,
well, each time you're sort of saying,
"Oh, I'm allocating a gig.
I'm allocating a gig. Allocating a gig," and
then the GC eventually has to come in and clean stuff up,
and then GC pauses the world and it says, "Hey.
I got to get rid of stuff,"
and then you start getting hit with that.
That's where it becomes really nasty
to deal without these sort of things like Span,
and that's one of the big motivations for
that whole set of stuff that's in the runtime,
and surfacing that up in the language.
>> Cool.
>> Yeah. Now you can do that all with
F sharp which is pretty great.
>> Nice. It's awesome. So, what are
the new features we have in 4.5?
>> We got a few other ones,
it's not just AsSpan.
As I said, I didn't cover everything with the Span work.
There's different representations of pointers,
there's the actual way to represent ByRefLike Struct.
So I'll just actually just show this really quickly.
You notice I got some compiler errors?
>> Yeah.
>> I'm defining a Struct here,
and it takes in two Spans
as inputs, and you're like, "Oh.
That should just work, right?".
>> Yeah.
>> Well, no.
Because Span is not just a Struct,
Span is a ByRefLike Struct.
It's something that has some special locks on it.
I guess you could say it sort of says, "No, no, no.
This thing lives on the stack.
This thing is allocated on the stack,
it stays on the stack,
you don't accidentally have it live on the heap somehow.
But this Struct, without specifying that it is ByRefLike,
gives you no guarantee
that you're going to be either on the stack or the heap,
you're just going to be allocated how you're allocated.
So in this case,
it's actually very simple,
just sort of add the additional attributes.
So Span is itself a ByRefLike Struct,
and so one of the rules with these is,
if you want to have it ByRefLike
Struct contained with another one,
you can't just stick it inside the class,
you can't just stick it anywhere you want.
It has to be inside of another ByRefLike Struct,
and that constraint is what allows basically
the runtime to do things a lot faster
than it would be able to do. So,-.
>> So you just annotated it with, is ByRefLike?
>> Yeah.
This is just a little attribute you stick on there.
So this does disallow you from doing really weird stuff.
So you can't start allocating
stuff on the heap inside of the Struct anymore.
This locks you down and they're saying, "No.
You're on the stack," but if that's something
that is of a benefit to your performance-wise,
then this is definitely a good thing.
So enough about that stuff,
because puff, it's just boring.
Nobody likes that, right? No. We got
a new keyword which is pretty fun.
>> New keywords?
>> Yeah, we got a new keyword and
another type here that
I'm going to show at the same time.
So people who use F sharp know
about Pattern Matching it's usually
one of their favorite features.
They also know about the Option Type.
Some of it or none of it
is basically wherever representing,
either if something can exist or nothing exists.
Well, that's Optional Type.
It's a Reference Type,
and we wanted to have a Struct version of that.
So we have it, it's called ValueSome and ValueNone.
It basically works the exact same way,
it's just it's a Struct rather than option,
sorry, rather than a Reference Type.
So if you're in sort of one of those scenarios
where a Structs is of a benefit to you,
performance-wise or whatever, then you can use that,
and not like a really big feature,
but just something that people
should be able to make some use out of.
>> That's right.
>> But, one of the things that people seem to really
love a lot when this came out,
and what's cool is, this is actually
a full community contribution,
is the new match bang keyword.
So I got this highlighted right here.
Now, this is slightly different than the match keyword.
So I'm going to walk through the first one.
So this first one, match under tryParseIntAsync,
because obviously it need to be
asynchronous to parse an integer, right?
>> Right.
>> So I'm just going to try parse and then produce
a ValueSome if I got it,
otherwise I produce a ValueNone.
So this is just okay.
Match on the value. Pretty straight-forward.
Most F sharp programmers know
how to do this all over the place.
It's usually one of the first things you learn how to
do when you're learning F sharp in the first place.
This is an asynchronous option.
This isn't just a value option that's being returned.
This is an async of value option.
This is the thing that's wrapping around it saying no,
this thing exists in an asynchronous context.
So to extract the underlying value,
you need to extract effectively out of that context,
and that's something that if you tried to write
without the matchmaking keyword today, like say,
I just got rid of that,
this isn't going to work because
I was expecting a value option,
but instead, I got an async of value option.
So, this basically just does that unwrapping.
Normally, you could write code,
you could you could do something like
let being V=tryParseIntAsync str,
and then, V itself is
going to be a value option then you could match on V,
but that's just boilerplate.
So you just inline, make that call there,
that simplifies a bit of extra code that you need.
>> Nice. So, I want to go back really quickly.
So, you said that this was a community contribution.
So, can we talk about that really quickly?
So, how does the community go along the routes of- oh,
hey, I think this is a cool feature and I'm
guessing F# is open source.
So we could put it on GitHub and
we create an issue
and then we start discussing it. Is that-.
>> Yes. So we actually have a full process in place.
So we have a repository called language suggestions,
and in the language suggestions repository,
you basically just file an issue saying,
hey, I think it'd be cool if you do this.
>> Yes.
>> We have a template that's like
it asks you questions to say, hey,
it summarize what's the thing that you want,
what are the reasons why you want this,
have you considered if this is a breaking change,
things like that to get people to
think about the problem a little bit.
Then, there's a discussion
and what we'll do is we'll go in,
we'll talk through it.
If we think it makes sense, we'll mark
it as approved and principle,
which is a way of saying,
we think this would make sense to
exist in the future F# language version.
>> Right.
>> Then, from that point forward, it's completely
open for anybody to say,
oh well, I can write a spec for this.
So, if you write the spec,
we have an RFC as we call it.
We have another RFCs repository
where everything is organized.
We have passed RFCs for
past language versions where
they're all organized in a little folder.
Then, we have just a regular folder called RFCs where
anything that's an active spec that
has not shipped yet exists.
So you can just add a new file there
and again, we have another template, and we say,
okay, we basically track back like
what's the suggestion that this write a spec for.
Then, we can write out everything there,
like what's the motivation,
what's the summary, what's the detailed design,
what are some additional things to consider,
what are some alternatives that you may have thought of,
what are some potential drawbacks to doing
this feature, things like that.
Then, once that's fleshed out in
an in-place for merge it, we'll say, okay,
the spec is there, and then,
it's up for anybody to
implement the actual compiler feature.
So in this case,
we had an open-source contributor
Jon Westenberg who came by,
and he said, "Yes, I'd like to do this.
I think this'd be pretty cool."
So the community talked about the matchmaking keyword.
They all seem to like it.
Then he said, "All right I'll write the
spec." So, he wrote the spec.
Then he said, "Okay, well,
I guess I'll write the poll requests."
So, we wrote the pull requests.
>> Nice.
>> We worked with him each of the stages.
He was really, really good.
When I say we worked with him, we barely
had to really do much just sort of said.
He would ask the question like,
"Oh hey, how do I do X?", and we'd say,
"Okay, just go right there", and then he'd go right
there and then implement it and it was of high-quality.
So, we decided when it was time
to grab the things that
we felt would make sense for a F# 4.5,
we said, okay, this is an open poll request
that is complete.
Everything seems to work, all the tests passed,
we tried it out, we think we like it, let's bring it in.
So we brought it in and then boom.
It's in there and
we get to do probably one of my favorite things,
which is when I write the release notes
to explain like something that came ou
in the next Visual Studio version or something
as specifically attribute him
as the person who implemented this whole thing.
So that was pretty cool.
Since then, he's actually implemented
other things and submitted to other RFC's,
other issues, that stuff.
So that's how the whole process works,
and that was something that I think is really cool.
It's just end to end from the beginning,
all the way until actually shipping.
This is a full community thing that we just
guided along until now everybody can use it.
>> It's really empowering for your
community too to see, hey,
this is not just something that we talk about doing,
like open source, this is real open-source.
>> Yes. You can contribute,
you can make suggestions,
you could be a part of the discussion,
and then eventually, you could
chip inside of Visual Studio.
>> Yes, yes, exactly.
What's interesting also is he actually did not use
Visual Studio to implement
any of this because he has Mac.
So he used VS for Mac,
but he didn't use just VS for Mac.
He was using the CLI, he was using-.
>> VS code.
>> -VS code, that stuff.
So, it was also cool
that not only he was a community person,
but this is not someone who is
using Visual Studio for Windows,
the old associations where it would get with .NET and F#.
He was fully and
this new cross-platform world
doing it all end-to-end which is really awesome.
>> That's awesome and this is so great to hear.
So I know we're running low on time.
Do you have any other cool little features
we could show just before we cut off?
>> Yes, yes. Just one little thing. I got
this little project called relaxation,
because I like to relax.
>> Relaxation, I like that.
>> So, this is just two little- I guess you could say
the compiler was just a little bit to
nitpicky prior to F# 4.5.
So In this case, I got basically,
a list of object.
So strings are also objects,
so due to the rules of inheritance,
you can say, I have a list
of objects and then it's comprised of strings.
If I wanted to combine that string character
with this yield expression,
I would actually need to explicitly cast
object prior to F# 4.5,
which is annoying because logically,
strings are objects so it should
just work well in F# 4.5,
it just works you don't have to do that.
>> You don't have to do that cast anymore.
>> Yes. Then another one,
so you'll notice that there's some indentation
going on here that might throw you off a little bit.
I have this starting bracket here for this array,
except it actually tad over rather than being right here.
>> Yes.
>> That's because in F# 4.1,
you had to actually do that.
So people would write code that looks like this,
which I think looks totally fine.
There's no reason for this not to exist this way,
but the compiler would say, "Oh,
you got a bad indentation",
and that doesn't make any sense.
So in F# 4.5,
we just made it so it doesn't do that anymore,
and this is actually something that
should help out people who use the fable compiler,
which is an F# to JavaScript transpiler.
It has a way to use F# syntax to model like a dom tree.
So, the way that you would syntactically model that is
you oftentimes align stuff vertically like this,
and so if people would want to do that,
and then the compiler would yell at them.
So, that's just a nice little goody
for people who were doing especially that stuff.
Those are the little relaxations
of syntax that we have with 4.5.
>> Cool. This was awesome, man.
Thank you so much for coming on the show, man.
>> Yes, yes, absolutely.
>> So this is another episode of ON.NET show.
We just had Philip telling us all about
the good stuff that's inside of F# 4.5.
Không có nhận xét nào:
Đăng nhận xét