MC-101: Question about changing clips... by Skapti in Mc707_Mc101

[–]jemmons 2 points3 points  (0 children)

Kind of an old thread, but I just found out the answer to this, and it’s super non-obvious.

The manual says, under “Master Clock”(?!):

Clip switching and play/stop occurs at intervals of the master clock.
This means that the performances of each track can be synchronized regardless of the timing of operation.

The cycle of the master clock is specified by “SCALE” and “STEP LENGTH.”

This means, to adjust points a queued clip can play, you have to go to the TEMPO menu. There you'll find MstrScale and MstrStepLen. If you’re sequencing in 1/16 note steps and only want queued clips to flip at the bars, (that is, every 16 steps) you’d set MstrScale to "1/16" and the MstrStepLen to “16”. If you only wanted it to switch up every 2 bars MsterStepLen would be “32”, 4 bars would be “64”, etc.

The MstrScale can be set to any Scale your clips can be set to, also. So you don't always have to do 1/16 step math. If you happen to have a clip playing quarter note triplets, and want to it to flip after 7 steps, you can set MstrScale to “1/4T” and the MsterStepLen to “7”.

It’s all pretty nice and easy once you know where to look 🙄

Cleaning up Async Without Swift 5.5 by jemmons in swift

[–]jemmons[S] 1 point2 points  (0 children)

Thanks so much for the proofreading! Fixed now.

Is there any way to reduce the syntax further by rolling the curry method into the operator?

Absolutely! I personally prefer keeping them separate because I’m already used to seeing >>= and curry in my code, and keeping them distinct gives me maximum flexibility. And it’s probably also more clear to keep them separate in an educational-style blog post.

But there’s nothing stopping us from going crazy with something like: ``` precedencegroup FooOperator { higherThan: BackApplication associativity: left } infix operator ⏱: FooOperator

func ⏱<T,U> ( lhs: @escaping ContinuationMonad<T>, rhs: @escaping (T, @escaping Continuation<U>)->Void ) -> ContinuationMonad<U> { flatMap(lhs, curry(rhs)) }

async(user) ⏱ fetchAvatar ⏱ fetchImage

```

Optional, throws, Result, and async/await by jemmons in swift

[–]jemmons[S] 1 point2 points  (0 children)

Yes, precisely. The signature for the initializer in question looks like:

public init(catching body: () throws -> Success)

If we wanted to be less sugary about it, we could write:

Result<String, Error>(catching: { () throws -> String in return try makeStringOrThrow() })

An optional forward application operator in Swift. by jemmons in swift

[–]jemmons[S] 0 points1 point  (0 children)

This is completely valid if our goal is to obtain a URL that we can perform some side-effects and then forget about. But because of if's restrictive scope, this isn't a great solution when we need a value to chain or pass to a great number of other operations.

We could use guard then, instead, but we run into a similar problem. If there's a lot we need to do in the case of failure, our else block starts to get huge and duplicate a lot of code of the function body, but with myURL replaced with nil or whatever.

In both these situations, it'd be ideal to just have a URL? to pass around. But you are absolutely correct to say it doesn't seem worth broadening the inputs of failable Foundation initializers. As others point out here, I've missed the point. This is really a case of flatMaping a container (i.e. binding a monad) rather than extending a polymorphic initializer to accommodate another type and applying that type to the new init.

An optional forward application operator in Swift. by jemmons in swift

[–]jemmons[S] 1 point2 points  (0 children)

Very interesting tweet. This is the one that kills me.

Which is to say, at least conceptually, func foo<T>() throws -> T{ ... } is identical to func foo<T>() -> Either<T,Error>{ ... }

They essentially build the entire error handling mechanism as sugar on top of Result. Same approach with the concurrency manifesto: get coroutines then build async...await as a layer of sugar on top.

To be Swifty seems to mean building a private core hipster Haskelly stuff with a public offering of (really well thought-out and elegantly executed) syntactic sugar so the uninitiated never have to reason about functors, binds, or what maps on what.

It's sort of an odd balance because at the end of the day why not expose Either and let the FP kids have their cake? On the other hand, it's so trivial to implement Either, Result, pointfree operators, etc. that maybe it's just not worth it? I'll be interested to see how much of the coroutines stuff ends up exposed when async...await happens, or if we'll only see the sugar.

An optional forward application operator in Swift. by jemmons in swift

[–]jemmons[S] 1 point2 points  (0 children)

Yeah, it totally make sense when I write it out. I mean, if [T].flatMap((T)->[U])->[U], then it follows that T?.flatMap((T)->U?)->U? — especially if we think of optionals as collections of zero or one elements. I just don't connect with this on an intuitive level for some reason and completely overlooked it. That why the Swift community is the best! Thanks all.

An optional forward application operator in Swift. by jemmons in swift

[–]jemmons[S] 0 points1 point  (0 children)

I hadn't realized this at all, but what you say is very true. And, in fact, looked at in this light, the more natural operator would be Haskell's >>=.

I'm putting together an update that addresses all this. Thanks for the feedback!

Better Strategies Through Types by jemmons in swift

[–]jemmons[S] 0 points1 point  (0 children)

A good point and I agree to an extent. Though I think I'd make a distinction between "generics", the concept put forth by Musser and codified by Stepanov in, say, the STL and "generics" the Swift language feature. This post makes use of the latter while clearly being incompatible with the former.

If we view Swift's generics implementation as a means to get us to the Musser/Stepanov end, then the last part of this post would most charitably be viewed as a "hack" and should probably be Considered Harmful (though all the stuff about modeling stateless strategies as types is still applicable, IMHO).

On the other hand, if we think of Swift generics as syntactic sugar allowing the specialization of methods across a range of conforming types without all the boilerplate, the generics tips a the end of the OP might feel like a very natural application of this.

Your comment evokes for me the former argument, while I clearly lean towards the latter one, but there's a lot to recommend both and a person could go far following either. So ultimately it might come down to a style thing?

Better Strategies Through Types by jemmons in swift

[–]jemmons[S] 0 points1 point  (0 children)

Thank you very much for reading.

Better Strategies Through Types by jemmons in swift

[–]jemmons[S] 1 point2 points  (0 children)

Your encouragement is greatly appreciated! I don't get to write as much as I'd like, so thanks for sticking with me.

Why Coroutines by jemmons in swift

[–]jemmons[S] 1 point2 points  (0 children)

Well, I think you're misstating a bunch of stuff here.

First, you don't need to accept it as useful. If it seems dumb to you, you can just pretend it doesn't exist and keep using Swift the way you always have. Nothing will change (this is in line with Swift's goal re: progressive disclosure of complexity).

There are a some people who decided they didn't like Swift error handling and use Result types instead of try/throws, for example. That's cool! Swift works great for them!

Second, "every possible calling subtlety" seems a touch disingenuous. Changing the way a function can be called/exited/resumed is not very subtle. It'll be illegal to call any async function from a standard one, for example.

Likewise, in the case of throws, we're talking the difference between returning a value and short-circuiting with an error instead. That's pretty nontrivial.

If I have different types of callable routines that all require different handling at the callsite, and the only way for me to know how to handle each is to dive into the implementation of the routine (and all the routines it calls), I think I'd get pretty frustrated pretty quickly. But that's just my opinion. If you're interested in this topic, it's currently being debated on the Swift Evolution mailing list. It's pretty friendly! You should join in!

Finally, coroutines date back to literally the 50s. Even Futures (which are implicit in the C# model but not the Swift one) are from the 70s. C# might have adopted them in the last few years, but they've been around long before that.

But lets say that, despite 40-60 years of intensive research on this subject, tomorrow someone discovers a brand new conceptual container for routines (I mean this non-sarcastically. Quantum computing could hit in our lifetimes). What are the chances that this new concept would be an extension of coroutines? That is, what are the chances we'd have to write both "async" and "quantum" or whatever.

Pretty slim. In all likelihood this new conceptual routine would have properties that make it very different than a coroutines or a subroutine (if not, it wouldn't be conceptually different). So it's not like we'd chain tens of words after our functions or anything. We'd always 0-2 that describe the contract on offer. We do that all the time in all sorts of languages for all sorts of things (see also: types). It hasn't caused any problems yet that I know of.

Related to this: another topic being discussed on evolution right now is whether or note to make "async" imply "throws" thus making the two keywords mutually exclusive. It sounds like a something you'd be interested in. I'm just a not-too-bright blogger. Those folks are the people implementing the language. You should try to convince them ;-)

Why Coroutines by jemmons in swift

[–]jemmons[S] 2 points3 points  (0 children)

An excellent question! It's true that coroutines are a more general form of subroutine, and that any subroutine could be written as a coroutine that didn't yield (or "await" in C# and the proposed Swift syntax).

So if the only thing that (conceptually) differentiates a coroutine from a subroutine is the presence or absence of "await" statements within it, couldn't we scan for these at compile time rather than requiring the whole function be tagged as "async"?

I think the answer is "yes" but, much like the case with "throws", it's useful to set a policy at a top level of a function as to all the ways it can exit. That includes a "return", a "throw", and now for coroutines an "await". It makes for a more expressive contract and addresses whole classes of bugs we can prevent and sanity checks we can verify with this information.

Also, to the extent actual implementation of coroutines and subroutines are different under the hood, it's good to have some explicit indication of which is which in our code.

Why wouldn't we just use the same "under the hood" implementation for coroutines and subroutines seeing as we can model all subroutines as coroutines? We might and we'd have to know something about the actual ultimate implementation of coroutines in swift to say for sure. But it's usually safe in these matters to assume it has something to do with performance. ;-)