I have an array of S-vectors and I want to do something like:

```
b .%5
```

and perform the `mod`

across all elements of each vector. So I built this:

```
function Base.rem(x::SVector{Float64},y::Float64)::SVector{Float64}
SVector(x[1]%y,x[2]%y)
end
```

and it didn’t work. It wasn’t until I modified it to be like:

```
function Base.rem(x::SArray{Tuple{2},Float64,1,2},y::Float64)::SArray{Tuple{2},Float64,1,2}
SVector(x[1]%y,x[2]%y)
end
```

that it worked for me. So I guess my question is exposing my lack of understanding of types. When I declare a variable to be an SVector, I do it like this:

```
vec:: SVector{2,Float64}
```

so why is the type different for the function definition I tried above? The issue is more general than just “How do I mod over an array of SVectors?” because I got it working. I think I just need help understanding types in general. (Yes, I’ll re-read the documentation on that too.)

Any thoughts or ideas to share?

Secondary question: Could I define `rem`

so that it would take an SVector of any length?

That’s not what what the `SVector`

type signature looks like — it is parameterized by *two* numbers, the length of the vector and the type of the elements. Since your code only works for an `SVector`

with two elements, you could do: `x::SVector{2,Float64}`

, for example.

But you seem to be making it much more complicated than necessary. Why not just do:

```
myrem(x::SVector, y::Number) = x .% y
```

which will do the elementwise `%`

that you want for any number of elements and any types? (I wouldn’t advise overloading `Base.rem`

, since that’s type piracy.)

(Realize that argument-type declarations and return-type declarations do *nothing* for performance here. Even with no argument-type declarations at all, Julia will compile a specialized version of the function for any argument types you pass. And it will infer the return type on its own.)

4 Likes

Hmm. OK, after playing a little bit I can see that this:

```
function Base.rem(x::SArray{T},y::Float64)::SArray{T} where {T}
SVector(map(x -> x%y,x))
end
```

works too and will work for vectors of any length. So, I think I’m confused about knowing how to declare a type correctly. How many arguments go inside the `{}`

and how can I figure that out?

The number (and kinds) of type parameters depends on the type. You have to look at the documentation (or the source code if there are no docs).

For example, this type has no parameters:

```
struct Foo
x::Float64
y::Float64
end
```

This has one parameter:

```
struct Bar{T}
x::T
y::T
end
```

and this has two parameters:

```
struct Baz{T,S}
x::T
y::S
end
```

In the case of StaticArrays, `SVector{n,T}`

is a simplified alias for `SArray{Tuple{n},T,n}`

, where `T`

is the element type and `n`

is the number of elements.

3 Likes

So why does this work:

```
function Base.rem(x::SVector,y::Float64)::SVector
SVector(map(x -> x%y,x))
end
```

Shouldn’t I be required to specify the type and number of elements in the type declaration?

Noted. Thank you. I guess I was just hoping to use the `%`

operator instead of a custom function. But I see your points

No. Any trailing type parameters that you omit can be anything.

`x::SVector`

means that `x`

can be `SVector{n,T}`

for any `n`

and `T`

. `x::SVector{2}`

means that `x`

can be an `SVector{2,T}`

for any `T`

.

5 Likes

Got it. Thanks for taking the time to school a newb. Much appreciated.

So is this type piracy?

```
struct Squares
count::Int
end
Base.iterate(S::Squares, state=1) = state > S.count ? nothing : (state*state, state+1)
```

If it is, what is the best way to build a custom iterator? If not, why not?

It’s only type piracy if you define iteration for types you don’t “own”. This example is fine because you own `Squares`

. The previous one, was redefining an operation in `Base`

for `Struct`

s defined in `StaticArrays`

.

4 Likes

I think I got it. So it’s type piracy even though there didn’t exist an operation in Base with type StaticArrays.

1 Like

Yes, because the function (`rem`

) is from `Base`

and the type (`SVector`

) is from `StaticArrays`

. So, if you did write this method in a package and someone loaded it, or you loaded a third-party package, and such package relied either in `rem`

failing for `SVector`

, or `rem`

calling a generic fallback that allowed for `SVector`

(like a fallback for `AbstractVector`

), the third-party package could start acting differently, what is considered spooky-action-at-a-distance and a bad practice.

4 Likes