The default is byValue for ALL types, but it is important to understand what the two options mean for a "reference type" (a class) as opposed to a value type. (structs).
For a reference type, if you declare a reference type variable in a method, that variable is a memory location in the stack frame of the method. It is not on the heap. When you initialize that variable (using new or a factory, whatever), then you have created an actual object on the heap, and the address of that object is stored in the declared reference variable in your methods stack frame.
When you pass a reference type to another method byVal, you are creating a copy of the address stored in the calling methods stack and passing the copy of that value (the pointer address) to the called method, where it is stored in a new memory slot in the called methods stack. Inside the called method, the new cloned variable points directly to the same object on the Heap. So using it can change the properties of the same object. But you cannot change which heap object the original reference variable (on the calling methods stack) points to.
If, in the called method I write
myVar = new object();
The original variable in the calling method will not have changed to point to a new object.
If I pass a reference type byRef, otoh, I am passing a pointer to the declared variable in the calling methods stack (which contains a pointer to the object on the heap) It is therefore a pointer to a pointer to the object. It points to the memory location on the calling methods stack, which points to the object on the heap.
So now, if I change the value of the variable in the called method, by setting it to a new object(), as above, since it is a "refereence" to the variable in the calling method, I am actually changing which object the variable in the calling method is pointing to. So After the called method returns, the variable in the calling method will no longer be pointing to the same original object on the heap.